标准Control.Monad.Writer.censor
是标准的双重标准
Control.Monad.Reader.local
,censor
修改编写者状态
在计算之后<{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 -> w
,tell
和listen
编写此函数。
我期望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
答案 0 :(得分:21)
我期望
censorWithResult
的准确行为是,如果ma :: Writer w a f :: a -> w -> w
和
runWriter ma = (r , y)
然后
runWriter (censorWithResult f ma) = (r , f r y)
好的,那就让我们这样做吧。您唯一需要知道的是writer
是runWriter
的左反。然后我们得到以下均衡链,首先将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)
如果我们只允许使用tell
,pass
和listen
,则唯一能够访问输出的功能是
-- | `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
内的操作执行给定操作,部分应用f
并pass
然后相应地修改输出。