不可能派生MonadWriter实例MonadWriter for Continuation Monad Transformer? [英] Impossible to derive Instance of MonadWriter for Continuation Monad Transformer?

查看:95
本文介绍了不可能派生MonadWriter实例MonadWriter for Continuation Monad Transformer?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试为继续Monad变换器的MonadWriter创建派生实例。
这是我的尝试:

$ $ p $ {code> { - #LANGUAGE MultiParamTypeClasses,FlexibleInstances,UndecidableInstances# - }

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


instance(MonadWriter wm)=> MonadWriter w(ContT r m)其中
tell = lift。告诉
监听m = ContT $ \ c - >
(a,w)< - listen $ runContT m(c)
return(a,w)

pass m = undefined


$ b

这给了我以下错误:

 发生检查:无法构造无限类型:r =(r,w1)
当概括'listen'的类型时
在`MonadWriter w(ContT rm)'的实例声明中'

接下来的尝试是这样的:

  instance(MonadWriter wm)=> MonadWriter w(ContT r m)其中
tell = lift。告诉
监听m = ContT $ \ c - >
(a,w)< - runContT m(listen.c)
return(a,w)

pass m = undefined


$ b

接下来是:

 发生检查:不能构造无限类型:a =(a,w)
当概括'listen'的类型时
在`MonadWriter w(ContT rm)'的实例声明中'

有谁知道如何实现listen和pass在这里?有没有理由为什么在mtl中没有实例声明?
请帮助我理解这一点!

问候
Marian



PS:
我发现 blog.sigfpe处的博客条目。 com),在讨论的
结尾的某个地方Edward Kmett说:
$ b

(...)我记得,通过'和'本地'会导致当前MTL出现问题,当你开始在ContT中混合时,可能应该将其分解为单独的类。 同样的举办也是为了收听MonadWriter。所以最简单的解决方案是,如果你不需要监听和传递特殊情况下,让它们不确定:

  instance(MonadWriter wm)=> MonadWriter w(ContT r m)其中
tell = lift。告诉
listen = undefined
pass = undefined

PS:(2011-03-03 -11)在这个主题中进一步讨论我已经提出了这个解决方案:
(当在ContT as()上指定r类型时,我们可以试试这个:)

  instance(MonadWriter wm)=> MonadWriter w(ContT()m)其中
监听m = do
a <-m
(_,w)< - lift $ listen $ runContT m(return。(const() ))
return(a,w)

编译!并且运行!但是,唉,一次行动必须计算两次。有人可能会以此暗示将两个电话合并为一个电话吗?然后我们将得到所需的实现。 解决方案

我不认为这是可能的。作为参考,这里的含义是 ContT

  ContT rma =( a→mr)→> mr 

这是我的出发点 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  - >做
rec(r,w)< - listen。 runContT m $ \x - > c(x,w)
返回r



<需要 LANGUAGE在上下文中,DoRec MonadFix m

虽然这种类型检测正确。 w 现在是由整个计算所写的值,而不仅仅是调用继续之前的部分 \x - > ; c(x,w)



你看到你需要做什么?我知道我的答案基本上是我认为这是不可能的,因为我不能想办法去做(Conal Elliott称之为缺乏想象力的证明),但我认为我这次缺乏想象是正确的。我们需要的信息在我们有机会窥视它之前就被销毁了。



我相信这个实例可以使用 montage转换器:

  newtype CodensityT ma = CodensityT {runCodensityT :: forall r。 (a  - > m r) - > mr} 

它可以提供与 Cont 在它的情况下,但不支持 callCC 。这是因为您可以在任何 r 的计算过程中使用 runCodensityT

  listen m = CodensityT $ \c  - > listen(runCodensityT m return)>> = c 

也许 callCC 是问题。如果你能想出一个结合 listen callCC 的例子,我就不会感到惊讶,这会产生一个悖论。

I try to make a derived instance for MonadWriter of the Continuation Monad Transformer. This is how i tried it:

{-# 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

This gives me the following error:

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)'

Next try was this:

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

Followed by:

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)'

Does anyone know how to implement listen and pass here? Is there a reason why there is no instance declaration for this in the mtl? Please help me to understand this!

Regards Marian

PS: I've found that Blog Entry at blog.sigfpe.com where somewhere at the end of the discussion Edward Kmett says:

"(...) As I recall, 'pass' and 'local' cause problems with the current MTL when you start mixing in ContT, and should probably be factored into separate classes."

Maybe the same hold's also for listen from MonadWriter. So the simplest solution is, if you dont need listen and pass in a special case, to leave them undefined:

instance (MonadWriter w m) => MonadWriter w (ContT r m) where
   tell= lift . tell
   listen = undefined
   pass = undefined

PS: (2011-03-11) Diving further in this subject I've come up with this solution: (When specifiying the type r on ContT as () we could try this:)

  instance (MonadWriter w m) => MonadWriter w (ContT () m) where    
    listen m = do
        a <- m
        (_,w) <- lift $ listen $ runContT m (return . (const ()))
        return (a,w)

This compiles! And runs! But, alas, the monadic action must be computed twice. May anybody take this as hint to collapse the two calls somehow into one? Then we will get the desired implementation.

解决方案

I don't think it's possible. For reference, here's the meaning of ContT:

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

Here's my starting point for listen:

listen m = ContT $ \c -> 
    runCont m (\x -> c (x,w))

The question is, where do we get w? w will come from the computation that runCont m performs before it calls our function \x -> c (x,w) with its return value x. That is, the information we need to pass to c comes from runCont, so we would need to do something like this:

listen m = ContT $ \c -> do
    rec (r,w) <- listen . runContT m $ \x -> c (x,w)
    return r

(Needs LANGUAGE DoRec and MonadFix m in the context)

Although that typechecks, it is not correct. w is now the value written by the entire computation, not just the portion before calling our continuation \x -> c (x,w).

Do you see what you would need to do? I know my answer is essentially "I think it's impossible because I can't think of a way to do it" (what Conal Elliott calls "proof by lack of imagination"), but I think my lack of imagination is correct this time. The information we need is destroyed before we have a chance to peek at it.

I believe this instance is possible with the Codensity monad transformer:

newtype CodensityT m a = CodensityT { runCodensityT :: forall r. (a -> m r) -> m r }

which gives you the same performance improvements as Cont in the cases where it does that, but doesn't support callCC. This is because you can runCodensityT in the middle of a computation with whatever r you want.

listen m = CodensityT $ \c -> listen (runCodensityT m return) >>= c

Maybe callCC is the problem. I wouldn't be surprised if you could come up with an example combining listen and callCC that would create a paradox.

这篇关于不可能派生MonadWriter实例MonadWriter for Continuation Monad Transformer?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆