4

继续寻求理解 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它下面的注释 k 调用替换 the,它会编译。这是怎么回事?

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

显然,这是原始代码的提炼版本,因此所有元素都有一个目的。感谢有关正在发生的事情以及如何解决它的解释性帮助。谢谢。

4

1 回答 1

6

这里的问题与 and 的类型有关wheneither与 ContT 无关:

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

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

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

使代码编译。这可能不是你想要做的,但它给了我们一个关于可能是错误的提示:k's type has been inferred to be something unpatable to when.

现在either来看签名:注意 to 的两个参数either必须是产生相同类型结果的函数。这里的类型return由 的类型决定x,而后者又由 on 的显式签名确定v。因此该(k . Left)位必须具有相同的类型;这反过来又修复了kat (GHC-determined)的类型

k :: Either String () -> ContT (Either String ()) IO [String]

这与when's 的期望不符。

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

k :: Either [Char] () -> ContT (Either [Char] ()) IO ()

这在when的书中很好。因此,代码编译。

作为最后一点,我使用 GHCi 的断点工具来获取这k两种场景下的确切类型——我远没有足够的专家来手写它们并以任何方式确保它们的正确性。:-):break ModuleName line-number column-number用来试一试。

于 2010-02-09T06:28:53.957 回答