Haskell 与 ContT、callCC 混淆,当

发布于 2024-08-21 03:13:09 字数 564 浏览 7 评论 0原文

继续寻求理解 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 调用,则它可以编译。这是怎么回事?

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

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

Continuing quest to make sense of ContT and friends. Please consider the (absurd but illustrative) code below:

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

This code does not compile. However, if the replace the when with the commented k call below it, it compiles. What's going on?

Alternatively, if I comment out the x2 line, it also compiles. ???

Obviously, this is a distilled version of the original code and so all of the elements serve a purpose. Appreciate explanatory help on what's going on and how to fix it. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只是我以为 2024-08-28 03:13:09

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

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

第二个参数需要是 m () 类型code> 对于一些 monad m。因此,可以像这样修改代码的 when 行:

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

以使代码编译。这可能不是您想要做的,但它给了我们一个关于可能出现错误的提示:k 的类型已被推断为 when 难以接受的类型。

现在对于 either 签名:请注意,either 的两个参数必须是产生相同类型结果的函数。这里return的类型由x的类型决定,而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 来尝试一下。

The problem here has to do with the types of when and either, not anything particular to ContT:

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

The second argument needs to be of type m () for some monad m. The when line of your code could thus be amended like so:

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

to make the code compile. This is probably not what you want to do, but it gives us a hint as to what might be wrong: k's type has been inferred to be something unpalatable to when.

Now for the either signature: notice that the two arguments to either must be functions which produce results of the same type. The type of return here is determined by the type of x, which is in turn fixed by the explicit signature on v. Thus the (k . Left) bit must have the same type; this in turn fixes the type of k at (GHC-determined)

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

This is incompatible with when's expectations.

When you comment out the x2 line, however, its effect on the type checker's view of the code is removed, so k is no longer forced into an inconvenient type and is free to assume the type

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

which is fine in when's book. Thus, the code compiles.

As a final note, I used GHCi's breakpoints facility to obtain the exact types of k under the two scenarios -- I'm nowhere near expert enough to write them out by hand and be in any way assured of their correctness. :-) Use :break ModuleName line-number column-number to try it out.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文