Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell:RWS上的一元不动点在遍历参数时是循环的_Haskell_Monads_Lazy Evaluation_Fixed Point Iteration_Monadfix - Fatal编程技术网

Haskell:RWS上的一元不动点在遍历参数时是循环的

Haskell:RWS上的一元不动点在遍历参数时是循环的,haskell,monads,lazy-evaluation,fixed-point-iteration,monadfix,Haskell,Monads,Lazy Evaluation,Fixed Point Iteration,Monadfix,我正在写一个程序,其中包括RWS,用于跟踪可变状态并生成一些日志。我的目的是定义一个计算,用于评估某个操作,收集后续状态,并根据它将某些内容附加到编写器的日志开头。最简单的例子: 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 -> p

我正在写一个程序,其中包括
RWS
,用于跟踪可变状态并生成一些日志。我的目的是定义一个计算,用于评估某个操作,收集后续状态,并根据它将某些内容附加到
编写器的日志开头。最简单的例子:

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)
这种行为对我来说很奇怪,我不明白为什么这个计算会发散。由于第二个变量中的
前置
在任何程度上都不会改变状态,因此更难证明这一点。为什么这个程序不收敛?我能做些什么来修复它吗


我知道我可以使用
状态
RWS
的一部分来解决它,但出于某种原因,我想避免它。

表单u
只有在定义了
s
时才被定义,但这里
s
mfix
传递的占位符,只有当整个计算
prepend s>>act>>get
终止时,才会定义

您的第一个版本可以工作,因为它不需要检查状态就可以将其配对

mfix::(a->ma)->ma
不接受严格的函数
f::a->ma
(即
f undefined=undefined

如果你有一系列的事情要告诉你,那么一个更懒散的方法就是在告诉他们之前把它们串联起来:

prepend s = tell (concatMap show s)

这是因为
表单
并不懒惰。此要求在中明确调用:函数必须是惰性的,以使不动点收敛。但是
表单
确实需要对其参数进行解构,以便对其进行迭代。它仍然可以对列表中的每个元素保持惰性,但列表本身却不能


当您运行此递归ish计算时,它需要三个步骤(即三个一元绑定):
prepend
,然后
act
,然后
get
,因此您基本上得到如下值:

[foldMap show s, "a", "b"]
其中,
foldMap show s
块尚未评估-即,它是指向
s
的砰砰声,这是相同计算的最终状态。在对状态求值之前,可以引用状态以将其合并到
foldMap show s
表达式中,因为Haskell是惰性的。这就是工作中的懒惰

但是,如果将
prepend
替换为
foldM
,则计算中不再有三个步骤(三个一元绑定)。现在,结果状态列表的每个元素都有一个步骤。这意味着为了构造计算(即定义其步骤,aka binds),您需要检查其自身的结果状态