Haskell与ContT混淆,callCC,何时

时间:2010-02-09 04:56:46

标签: haskell monads continuations

继续寻求理解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

此代码无法编译。但是,如果用它下面的注释k调用替换when,它就会编译。发生了什么事?

或者,如果我注释掉x2行,它也会编译。 ???

显然,这是原始代码的精炼版本,因此所有元素都有用。对正在发生的事情以及如何解决问题提供解释性帮助。感谢。

1 个答案:

答案 0 :(得分:6)

此处的问题与wheneither的类型有关,而与ContT无关:

when :: forall (m :: * -> *). (Monad m) => Bool -> m () -> m ()
either :: forall a c b. (a -> c) -> (b -> c) -> Either a b -> c

对于某些monad m (),第二个参数必须是m类型。因此,代码的when行可以像这样进行修改:

when True $ k (Left "Error message 2") >> return ()

使代码编译。这可能不是你想要做的,但它给了我们一个可能出错的提示:k的类型被推断为when不适合的东西。

现在为either签名:注意either的两个参数必须是产生相同类型结果的函数。此处return的类型由x的类型决定,而v的类型又由(k . Left)上的显式签名确定。因此k位必须具有相同的类型;这反过来又修复了k :: Either String () -> ContT (Either String ()) IO [String] 的类型(GHC确定)

when

这与x2的期望不相符。

但是,当您注释掉k行时,会删除其对类型检查器的代码视图的影响,因此k :: Either [Char] () -> ContT (Either [Char] ()) IO () 不再被强制为不方便的类型,并且可以自由地假设型

when

k的书中很好。因此,代码编译。

作为最后一点,我使用了GHCi的断点工具来获得两种情况下:break ModuleName line-number column-number的确切类型 - 我远远不够专业,无法用手写出来并以任何方式保证他们的正确性。 :-)使用{{1}}进行试用。

相关问题