继续寻求使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线,它也编译。 ???

显然,这是原来的码的蒸馏水版本等的所有元素的服务于一个目的。不胜感激这是怎么回事,如何解决它解释帮助。感谢。

有帮助吗?

解决方案

这里的问题有同类型wheneither的,不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尝试一下。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top