我如何编写这个更通用的版本`Control.Monad.Writer.censor`?

时间:2014-01-30 04:54:54

标签: haskell monads

标准Control.Monad.Writer.censor是标准的双重标准 Control.Monad.Reader.localcensor修改编写者状态 计算之后<{1}}修改阅读器状态 之前计算:

local

然而,censor :: (w -> w) -> Writer w a -> Writer w a local :: (r -> r) -> Reader r a -> Reader r a Reader monad并不完全 对称的。即,编写器计算产生结果,in 除了作家国家,我正在尝试写一个替代方案 利用这种不对称性的Writer版本。我想要 写一个函数

censor

采用接收到的censorWithResult :: (a -> w -> w) -> Writer w a -> Writer w a 类型的转换器 计算结果另外到写入器状态。我不 了解如何使用a -> w -> wtelllisten编写此函数。

我期望pass的准确行为是,如果

censorWithResult

ma :: Writer w a
f  :: a -> w -> w

然后

runWriter ma = (r , y)

,而

runWriter (censorWithResult f ma) = (r , f r y)

runWriter (censor g ma) = (r , g y)

实施例

这对于理解这个问题不是必要的,但这里是一个 简化版的激励示例:

g :: w -> w

2 个答案:

答案 0 :(得分:21)

  

我期望censorWithResult的准确行为是,如果

ma :: Writer w a
f  :: a -> w -> w
     

runWriter ma = (r , y)
     

然后

runWriter (censorWithResult f ma) = (r , f r y)

好的,那就让我们这样做吧。您唯一需要知道的是writerrunWriter的左反。然后我们得到以下均衡链,首先将writer应用于两侧,然后消除左逆。

        runWriter (censorWithResult f ma)  =        (r, f r y)
writer (runWriter (censorWithResult f ma)) = writer (r, f r y)
                   censorWithResult f ma   = writer (r, f r y)

我们现在唯一需要做的就是插入等式runWriter ma = (r, y)

censorWithResult f ma = let (r, y) = runWriter ma in writer (r, f r y)

不是等式推理吗?

答案 1 :(得分:5)

如果我们只允许使用tellpasslisten,则唯一能够访问输出的功能是

-- | `pass m` is an action that executes the action `m`, which returns a value
-- and a function, and returns the value, applying the function to the output. 
pass :: (MonadWriter w m) => m (a, w -> w) -> m a

因此对于censorWithResult,我们需要部分应用a -> w -> w类型的给定函数来获取w -> w并将其处理为pass。这可以作为

完成
censorWithResult :: (MonadWriter w m) => (a -> w -> w) -> m a -> m a
censorWithResult f m = pass $ do
    a <- m
    return (a, f a)

pass内的操作执行给定操作,部分应用fpass然后相应地修改输出。