Haskell 与 ContT、callCC 的混淆,当

标签 haskell monads continuations

继续寻求理解 ContT 和 friend 的意义。请考虑下面的( absurd 但说明性的)代码:

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 调用,它编译。这是怎么回事?

或者,如果我注释掉 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 ()对于一些 monad 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 时行,然而,它对代码的类型检查器 View 的影响被删除,所以 k不再被迫进入不方便的类型并且可以自由承担类型
k :: Either [Char] () -> ContT (Either [Char] ()) IO ()

这在 when 中很好的书。这样,代码就编译通过了。

最后要注意的是,我使用 GHCi 的断点工具来获取 k 的确切类型。在这两种情况下——我远不够专家,无法用手把它们写出来,并以任何方式确保它们的正确性。 :-) 使用 :break ModuleName line-number column-number试试看。

关于Haskell 与 ContT、callCC 的混淆,当,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2226833/

相关文章:

f# - 如何在 F# 中将两个(双选项)相乘

haskell - 这是对 ContT 的适当使用吗?

python - 通过隐式知道 Python 中的回调/调用函数是什么来减少函数计算的最简洁方法?

haskell - 如何使用CallStack抛出异常?

opengl - 传递给 OpenCL 内核时 image2d_t 损坏

haskell - 如何使用非 IO "exterior"构建 Monad,但 IO "interior"?

scheme - 为什么延续过去的风格

haskell - 无法在终端中运行 ghci

haskell - 为什么 Haskell 函数不能返回一个列表

haskell - 状态单子(monad)和 learnyouahaskell.com