List 如何制作;时间机器“;在哈斯克尔工作?

List 如何制作;时间机器“;在哈斯克尔工作?,list,haskell,recursion,List,Haskell,Recursion,我听说在Haskell中,我们可以使用MonadFix访问一个值,该值将在将来进行评估。但是我认为Monads只是语法糖,所以应该有类似的东西可以在纯函数中实现。因此,我尝试了以下方法: timemachine :: [a] -> (a -> Int -> b -> b) -> b -> b timemachine al f b = result where ~(total, result) = foldr app (0,b) al app a

我听说在Haskell中,我们可以使用
MonadFix
访问一个值,该值将在将来进行评估。但是我认为
Monad
s只是语法糖,所以应该有类似的东西可以在纯函数中实现。因此,我尝试了以下方法:

timemachine :: [a] -> (a -> Int -> b -> b) -> b -> b
timemachine al f b = result where
    ~(total, result) = foldr app (0,b) al
    app a (i,b1) = (i+1, f a (total - i) b1)

main :: IO ()
main = print $ timemachine "ddfdfeef" (\x i y -> (x,i):y) []
但产出并非预期:

[('d',1),('d',2),('f',3),('d',4),('f',5),('e',6),('e',7),('f',8)]
理想情况下,结果应该是

[('d',8),('d',7),('f',6),('d',5),('f',4),('e',3),('e',2),('f',1)]

我做错了什么吗?

跳过关于
MonadFix
的部分,似乎您希望使用至少部分需要构造的值(
total
基于折叠,而折叠又基于
total

实际上你已经在做了,只是你的期望值与你的折叠不一致!要查看问题,您可以将计时器更改为

timemachine al f b = result where
   ~(total, result) = foldr app (0,b) al
   app a (i,b1) = (i+1, f a i b1)
产生

[('d',7),('d',6),('f',5),('d',4),('f',3),('e',2),('e',1),('f',0)]
因此,
total-i
起作用了,只是你积累的
i
s不是你想要的

现在,为什么?好的,您使用一个
foldr
,其结果如下:

app 'd' (app 'd' (app 'f' ... (app 'f' (0,b)))))))))
因此,
app
正在进行的计数是从列表右侧开始计算的。如果我们将其改为一个
foldl
,它从另一侧运行列表,并将代码的其余部分更改为与之对齐:

timemachine :: [a] -> (a -> Int -> b -> b) -> b -> b
timemachine al f b = result where
  ~(total, result) = foldl app (0,b) al
  app (i,b1) a = (i+1, f a (total-i) b1)

main :: IO ()
main = print $ timemachine "ddfdfeef" (\x i y -> y++[(x,i)]) []
你得到了你想要的:

[('d',8),('d',7),('f',6),('d',5),('f',4),('e',3),('e',2),('f',1)]

你为什么期望这样的结果?惰性(?)从代码中何而来?我的实现可能完全错误,但有没有正确的方法来获得预期的结果?关键是我需要从未来访问一个值——在上面的示例中,是列表的长度。如果我理解正确,您要求使用
MonadFix
对某些代码进行解压缩。你给我们的是原版,这似乎很公平。:-)我应该改用
foldl'
吗?我听说应该避免使用
foldl
。通常使用
foldl'
比使用
foldl
更好,因为它的累加器很严格,当你向左折叠时,你通常对懒惰不感兴趣。然而,在这种情况下,有两个问题:1。我们的累加器是一对,并且
seq
(由
fold'
使用)只计算HNF,而
app
已经计算了HNF,因此没有严格性增益。2.我们对懒惰感兴趣,正是懒惰让我们成功。如果我们使用类似于
deepseq
的东西进行折叠,它会过早地对结果列表进行评估,而且不会完成。@EartEngine请原谅该答案的格式不好,我不知道5分钟的注释编辑窗口。我希望它仍然清楚地回答你的问题!