假设我想要一个用变量计算表达式的计算。我希望它在传递给它的运行器的env中看起来变量,并且还有某种状态和日志。我带了一个algebra,用RWS
胡椒,我已经完成了。
除lookup
返回Maybe
。
所以我需要一个monad堆栈。
λ type EvalA = MaybeT (RWS () () ()) ()
λ runRWS (runMaybeT (MaybeT (return (Just ())) :: EvalA )) () ()
(Just (),(),())
λ runRWS (runMaybeT (MaybeT (return Nothing) :: EvalA )) () ()
(Nothing,(),())
到目前为止一切顺利。但是这种类型有些混乱:变压器位于Identity
之上的变压器顶部。为什么不翻转它。
λ type EvalB = RWST () () () Maybe ()
λ runRWST (return () :: EvalB) () ()
Just ((),(),())
λ runRWST (Nothing :: EvalB) () ()
<interactive>:12:10: error:
• Couldn't match type ‘Maybe a0’ with ‘RWST () () () Maybe ()’
Expected type: EvalB
Actual type: Maybe a0
..........
λ -- ...?
暂且没有Nothing
加上日志比单独使用Nothing
更好,我怎样才能从Nothing
获得EvalB
?
答案 0 :(得分:3)
你需要lift
,这是monad变形金刚支持的基本操作。
ghci> runRWST (lift Nothing) () ()
Nothing
但也要小心做这种交换。 Maybe
不与RWS
通勤。事实上,它并没有与任何人通勤!例如:
WriterT w Maybe a
≃ Maybe (a, w)
但
MaybeT (Writer w a)
≃ Writer w (Maybe a)
≃ (Maybe a, w)
在前者中,Maybe
作为基本monad,Nothing
值会删除作者的日志 - 你得到的只是失败。在后者中,以Writer
为基础,计算可能会失败,但仍会在日志中生成一个值。
一个非常好的练习是对Reader
,Writer
和State
中的每一个执行此操作,并找到可在MaybeT m
,{mT Maybe
之一中表示的计算{1}}但不是另一个。