我正在编写一个涉及RWS
的程序,用于跟踪可变状态并生成一些日志。我的目的是定义一个计算,该计算对某些操作进行评估,收集后继状态,并根据该状态将某些内容附加到Writer
日志的beginning中。最小示例:
type M = RWS () String [Int]
run a = evalRWS a () []
prepend s = tell (foldMap show s)
act = do
tell "a"
modify (1:)
tell "b"
comp = mfix $ \s -> prepend s >> act >> get
这里,我使用MonadFix
通过在act
发生之前写日志来改变过去。它完美地返回"1ab"
。但是,如果我使用M
遍历状态,则会挂起:
prepend s = forM_ s (tell . show)
这种行为对我来说很奇怪,我不明白为什么这种计算会有所不同。由于第二种变体中的prepend
不会在任何程度上改变状态,因此更难辩解。为什么该程序不收敛?我有什么可以解决的(inb4“ hehe fix”)吗?
[我知道我可以使用State
的RWS
部分来解决它,但是由于某些原因,我想避免使用它。
仅在定义了forM_ s u
的情况下才定义[s
,但是这里s
是mfix
传递的占位符,仅当整个计算prepend s >> act >> get
终止时才定义它。
您的第一个版本有效,因为它不需要检查状态就可以成对放置。
[mfix :: (a -> m a) -> m a
不接受严格的功能f :: a -> m a
(即f undefined = undefined
)。]]
如果您有要tell
的事物列表,那么一种比较懒惰的方法是在告诉它们之前将它们连接起来:
prepend s = tell (concatMap show s)
这是因为forM_
不是lazy