为什么折叠包含 undefined 的列表时 foldr 不返回 undefined?

问题描述

我无法理解以下原因:

foldr (\x y -> x && y) True [False,undefined,True]

不是给我一个undefined例外。

我的看法是,foldr 比较 True 和列表的最后一个元素,即 True,因此返回 True,现在将其与 { 进行比较{1}}。如果操作涉及 undefined 类型,Haskell 会忽略它吗?如果在匿名函数中我们有 undefined 而不是 True,我会理解输出x || y,因为编译器会看到其中一个运算符已经设置为 {{1 }},但由于我们使用的是 (&&),因此必须检查两个值是否都设置为 True 或其中之一设置为 (&&),对吗?

关于它为什么返回 True 的任何线索?

解决方法

它并没有忽略 undefined,而是从未见过 undefined

foldr 的真正定义稍微复杂一些,但我们可以假设它(部分)定义为

foldr f z (x:xs) = f x (foldr f z xs)

因此,经过一步,我们有

foldr (&&) True [False,undefined,True]
  == False && foldr (&&) True [undefined,True]

False && _ == False 开始,无需计算对 foldr 的递归调用,因此无需对 undefined 执行任何操作。


undefined 仅在评估时引发异常。不需要评估它来定义列表 [False,True],它是 False : undefined : True : [] 的语法糖,而 (:) 的第二个参数是惰性的。

,

代码等价于

let {w = [head w,True]} in foldr (&&) True (False:w)
===
let {w = [head w,True] ; 
     r = foldr (&&) True w} in False && r
===
let {r=r} in False
===
False

foldr 创建的计算仅在组合函数的第二个(右)参数是严格的情况下从右开始处理输入列表。

这里 (&&) 不是。它是“短路”,如果它的第一个参数是 False,它会立即返回 False,因为它确实在这里。永远不会强制使用 r,因为不需要它的值。