gpt4 book ai didi

haskell - Kleisli 组合并折叠无限列表

转载 作者:行者123 更新时间:2023-12-02 06:50:12 26 4
gpt4 key购买 nike

在尝试使用 Haskell 定义从连接 channel 读取的无限循环时,我想到了使用单子(monad)的 Kleisli 组合折叠部分应用函数的无限列表的想法。这个想法似乎合理且简单,但我遇到了一个奇怪的场景,显然正在评估无限列表,而不是等待输入。

我创建了以下示例来说明我的问题:

loop :: Int -> IO Int
loop s = (foldr (<=<) return (repeat process)) s

process :: Int -> IO Int
process i = do
putStrLn $ show i
x <- getLine
return $ i + 1

main = loop 0

当我运行上面的代码时,GHCi 在堆栈溢出后停止。它不等待“getLine”。当我将 <=< 替换为 >=> 时,它按预期工作:列表将仅在每个“getLine”之后逐个元素获取评估元素。

为什么会这样?我的 foldr 初始值是 return,它不应该给它添加任何副作用,并且根据 monad 法则,使用 <=< 和 >=> 的左右身份应该保证相同的行为。

最佳答案

您不能从末尾开始访问无限列表——没有尽头。

你的代码构建

action0 <=< (action1 <=< (action2 ....))

具有正确的结合性,但是 x <=< y (粗略地说)运行 y之前x .

使用 >=>使计算从 action0 开始如预期的那样。

与此比较:

cons x xs = x : xs
snoc x xs = xs ++ [x]

foldr cons [] [1..] = [1..]
foldr snoc [] [1..] = _|_

这并不奇怪,因为 foldr snoc [] = reverse ,而且我们无法反转无限列表。

这里的问题是 snoc评估尾部 xs之前x , 所以 foldr在考虑手头的元素之前评估对尾列表的“递归调用”。

在 monadic 情况下事情更复杂,但一般原则在精神上是相似的。使用 foldr (<=<) return (repeat action)类似于

loop x = do
x' <- loop x
action x'

相反,foldr (>=>) return (repeat action)类似于

loop x = do
x' <- action x
loop x'

关于haskell - Kleisli 组合并折叠无限列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47042300/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com