哈斯克尔混淆ContT,callCC,当
-
19-09-2019 - |
题
继续寻求使ContT和朋友的感觉。请考虑以下的(荒诞而是说明性的)代码:
v :: IO (Either String [String])
v = return $ Left "Error message"
doit :: IO (Either String ())
doit = (flip runContT return) $ callCC $ \k -> do
x <- liftIO $ v
x2 <- either (k . Left) return x
when True $ k (Left "Error message 2")
-- k (Left "Error message 3")
return $ Right () -- success
此代码不编译。但是,如果与它下面的评论ķ呼叫更换when
,它编译。这是怎么回事?
可选地,如果我注释掉X2线,它也编译。 ???
显然,这是原来的码的蒸馏水版本等的所有元素的服务于一个目的。不胜感激这是怎么回事,如何解决它解释帮助。感谢。
解决方案
这里的问题有同类型when
和either
的,不ContT什么特别的事:
when :: forall (m :: * -> *). (Monad m) => Bool -> m () -> m ()
either :: forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
的第二个参数需要是类型m ()
一些单子m
的。代码的when
线因此可以修正像这样:
when True $ k (Left "Error message 2") >> return ()
使代码编译。这可能不是你想要做什么,但它给我们一个提示,什么可能是错误的。k
的类型被推断为是when
东西难吃
现在为either
签名:注意到两个参数either
必须是产生相同类型的结果的功能。该类型return
这里被x
的类型,其又通过v
明确的签名固定确定。因此,(k . Left)
位必须有相同的类型;这反过来又固定k
的类型在(GHC确定的)
k :: Either String () -> ContT (Either String ()) IO [String]
这是与when
的期望不兼容。
当您注释掉x2
线,但是,其上的代码的类型检查器的视图效应被去除,所以k
不再被迫进入一个不方便的类型和可自由假设的类型
k :: Either [Char] () -> ContT (Either [Char] ()) IO ()
这是在when
的书细。因此,代码编译。
最后一点,我用GHCI的断点设施,以获得这两种情况下的确切类型k
的 - 我是远不足够的专家通过手工把它们写出来,是保证其正确性的任何方式。 :-)使用:break ModuleName line-number column-number
尝试一下。
不隶属于 StackOverflow