为什么foldright适用于无限列表?

adr*_*nmc 3 language-agnostic haskell functional-programming fold

我的印象是foldright从列表的末尾开始并向后工作(这就是我想象的右关联意味着什么).所以我很困惑,以下适用于无限列表.

我有一个功能find:

find :: (a -> Bool) -> List a -> Optional a
find p = foldRight (\c a -> if p c then Full c else a) Empty
Run Code Online (Sandbox Code Playgroud)

请注意以下工作:

>> find (const True) infinity
Full 0
Run Code Online (Sandbox Code Playgroud)

我做了一些搜索,发现这篇文章:你怎么知道何时使用fold-left以及何时使用fold-right?

不幸的是,接受的答案并不是特别有用,因为右关联操作的例子是:

A x (B x (C x D))
Run Code Online (Sandbox Code Playgroud)

这仍然意味着它需要首先执行最正确的事情.

我想知道是否有人能为我解决这个问题,谢谢.

ram*_*ion 11

让我们从一个函数开始:

>>> let check x y = if x > 10 then x else y
>>> check 100 5
100
>>> check 0 5
5
Run Code Online (Sandbox Code Playgroud)

check有两个参数,但可能不会使用它的第二个参数.由于haskell是惰性的,这意味着永远不会评估第二个参数:

>>> check 20 (error "fire the missles!")
20
Run Code Online (Sandbox Code Playgroud)

这种懒惰让我们跳过了可能无限量的工作:

>>> check 30 (sum [1..])
30
Run Code Online (Sandbox Code Playgroud)

现在让我们逐步foldr check 0 [0..]使用等式推理:

foldr check 0 [0..]
= check 0 (foldr check 0 [1..]) -- by def'n of foldr
= foldr check 0 [1..] -- by def'n of check
= check 1 (foldr check 0 [2..]) -- by def'n of foldr
= foldr check 0 [2..] -- by def'n of check
-- ...
= foldr check 0 [10..]
= check 10 (foldr check 0 [11..]) -- by def'n of foldr
= foldr check 0 [11..] -- by def'n of check
= check 11 (foldr check 0 [12..]) -- by def'n of foldr
= 11 -- by def'n of check
Run Code Online (Sandbox Code Playgroud)

注意懒惰如何强迫我们从上到下进行评估,看看最外层函数调用如何(以及如果)使用其参数,而不是自下而上(在将它们传递给函数之前评估所有参数),如同严格语言呢.

  • adrianmc-您完全掌握了它 (2认同)