Haskell与ContT混淆,callCC,何时

me2*_*me2 4 monads continuations haskell

继续寻求理解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
Run Code Online (Sandbox Code Playgroud)

此代码无法编译.但是,如果when用它下面的注释k调用替换它,它就会编译.这是怎么回事?

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

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

Mic*_*zyk 6

这里的问题有同类型的做wheneither,没有什么特别ContT:

when :: forall (m :: * -> *). (Monad m) => Bool -> m () -> m ()
either :: forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Run Code Online (Sandbox Code Playgroud)

第二个参数需要是m ()某些monad 的类型m.因此when,您的代码行可以像这样修改:

when True $ k (Left "Error message 2") >> return ()
Run Code Online (Sandbox Code Playgroud)

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

现在either签名:注意两个参数either必须是产生相同类型结果的函数.该类型的return这里是由的类型决定x,而这又通过明确的签名固定v.因此,该(k . Left)位必须具有相同的类型; 这反过来又修正了kat 的类型(GHC确定)

k :: Either String () -> ContT (Either String ()) IO [String]
Run Code Online (Sandbox Code Playgroud)

这与when预期不符.

x2然而,当您注释掉该行时,它对类型检查器的代码视图的影响被删除,因此k不再强制进入不方便的类型并且可以自由地假设类型

k :: Either [Char] () -> ContT (Either [Char] ()) IO ()
Run Code Online (Sandbox Code Playgroud)

when本书很好.因此,代码编译.

作为最后一点,我使用了GHCi的断点设施来获得k两种情况下的确切类型- 我不够专业,无法用手写出来并以任何方式确保它们的正确性.:-) :break ModuleName line-number column-number用来尝试一下.