gpt4 book ai didi

haskell - 无法为 Continuation Monad Transformer 派生 MonadWriter 的实例?

转载 作者:行者123 更新时间:2023-12-03 15:06:42 24 4
gpt4 key购买 nike

我尝试为 Continuation Monad Transformer 的 MonadWriter 创建一个派生实例。
这就是我尝试的方式:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}

import Control.Monad.Cont
import Control.Monad.Writer


instance (MonadWriter w m) => MonadWriter w (ContT r m) where
tell= lift . tell
listen m= ContT $ \ c -> do
(a,w) <- listen $ runContT m (c)
return (a,w)

pass m = undefined

这给了我以下错误:
Occurs check: cannot construct the infinite type: r = (r, w1)
When generalising the type(s) for `listen'
In the instance declaration for `MonadWriter w (ContT r m)'

下一次尝试是这样的:
instance (MonadWriter w m) => MonadWriter w (ContT r m) where
tell= lift . tell
listen m= ContT $ \ c -> do
(a,w) <- runContT m (listen . c)
return (a,w)

pass m = undefined

其次是:
Occurs check: cannot construct the infinite type: a = (a, w)
When generalising the type(s) for `listen'
In the instance declaration for `MonadWriter w (ContT r m)'

有谁知道如何在这里实现监听和传递?是否有理由在 mtl 中没有为此的实例声明?
请帮助我理解这一点!

问候
玛丽安

PS:
我发现 Blog Entry at blog.sigfpe.com在某个地方
讨论结束 Edward Kmett 说:

“(...)我记得,当你开始在 ContT 中混合时,'pass' 和 'local' 会导致当前 MTL 出现问题,并且可能应该将其分解为单独的类。”

也许从 MonadWriter 也可以听到同样的声音。所以最简单的解决方案是,如果您不需要在特殊情况下监听和传递,则将它们保留为未定义:
instance (MonadWriter w m) => MonadWriter w (ContT r m) where
tell= lift . tell
listen = undefined
pass = undefined

PS:(2011-03-11)进一步研究这个主题我想出了这个解决方案:
(当将 ContT 上的类型 r 指定为 () 时,我们可以试试这个:)
  instance (MonadWriter w m) => MonadWriter w (ContT () m) where    
listen m = do
a <- m
(_,w) <- lift $ listen $ runContT m (return . (const ()))
return (a,w)

这编译!并跑!但是,唉,一元 Action 必须计算两次。有人可以将此作为暗示以某种方式将这两个电话合二为一吗?然后我们将获得所需的实现。

最佳答案

我不认为这是可能的。供引用,这里是ContT的意思:

ContT r m a = (a -> m r) -> m r

这是我的 listen 的起点:
listen m = ContT $ \c -> 
runCont m (\x -> c (x,w))

问题是,我们从哪里得到 w ? w将来自 runCont m 的计算在调用我们的函数 \x -> c (x,w) 之前执行及其返回值 x .也就是我们需要传递给 c的信息来自 runCont ,所以我们需要做这样的事情:
listen m = ContT $ \c -> do
rec (r,w) <- listen . runContT m $ \x -> c (x,w)
return r

(需要 LANGUAGE DoRecMonadFix m 在上下文中)

尽管进行了类型检查,但它是不正确的。 w现在是整个计算写入的值,而不仅仅是调用我们的延续 \x -> c (x,w) 之前的部分.

你知道你需要做什么吗?我知道我的回答基本上是“我认为这是不可能的,因为我想不出办法”(Conal Elliott 称之为“缺乏想象力的证明”),但我认为这次我缺乏想象力是正确的。我们需要的信息在我们有机会偷看之前就被破坏了。

我相信 Codensity monad 转换器可以实现这种情况:
newtype CodensityT m a = CodensityT { runCodensityT :: forall r. (a -> m r) -> m r }

它为您提供与 Cont 相同的性能改进在它这样做但不支持 callCC 的情况下.这是因为您可以 runCodensityT在计算过程中使用任何 r你要。
listen m = CodensityT $ \c -> listen (runCodensityT m return) >>= c

也许 callCC是问题所在。如果你能想出一个结合 listen 的例子,我不会感到惊讶。和 callCC这将造成一个悖论。

关于haskell - 无法为 Continuation Monad Transformer 派生 MonadWriter 的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5166601/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com