List 为什么折叠包含未定义的列表时foldr不返回未定义?

List 为什么折叠包含未定义的列表时foldr不返回未定义?,list,haskell,lazy-evaluation,evaluation,fold,List,Haskell,Lazy Evaluation,Evaluation,Fold,我很难理解为什么会出现以下情况: foldr (\x y -> x && y) True [False,undefined,True] 是不是给我一个未定义的异常 在我看来,foldr将True与列表的最后一个元素(即True)进行比较,从而返回True,现在将其与未定义的进行比较。如果操作涉及未定义的类型,Haskell是否会忽略该操作?如果在匿名函数中我们使用了x|124; y而不是(&&&),我会理解输出是True,因为编译器会看到其中一个操作符已经设置为True,

我很难理解为什么会出现以下情况:

foldr (\x y -> x && y) True [False,undefined,True]
不是给我一个
未定义的
异常

在我看来,
foldr
True
与列表的最后一个元素(即
True
)进行比较,从而返回
True
,现在将其与
未定义的
进行比较。如果操作涉及未定义的
类型,Haskell是否会忽略该操作?如果在匿名函数中我们使用了
x|124; y
而不是
(&&&)
,我会理解输出是
True
,因为编译器会看到其中一个操作符已经设置为
True
,但是因为我们使用的是
(&&&)
必须检查这两个值是否都设置为
True
或其中一个设置为
False
,对吗


关于它为什么返回
False

的任何线索,它都不会忽略
未定义的
,因为
未定义的
从未被发现

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

因此,经过一步,我们有了

foldr (&&) True [False, undefined, True]
  == False && foldr (&&) True [undefined, True]
由于
False&&&u==False
,因此不需要计算对
foldr
的递归调用,因此不需要对
未定义的
执行任何操作



undefined
仅在对异常进行求值时才会引发异常。定义列表
[False,undefined,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
,因为它的值是不需要的。

未定义的
永远不会被忽略,除非在这种情况下,所有可能的值都会被忽略。
未定义::a
不是类型,而是
Bool
类型的值(在您的情况下)。事实上,Haskell中的每个类型都有一个附加值,称为⊥ 或者<代码>布尔值
因此有3个(!)值
真、假,⊥
foldr
不是从列表的最后一个元素开始吗?例如:
True
和&
True
,然后是
未定义的
,最后是
False
否,这就是
foldl
r
指的是在对结果和剩余元素应用fold函数之前递归折叠哪个部分。这是一个常见的误解,在我第一次看到它时,它愚弄了我一分钟。但是
foldl
foldl
都是从列表的第一个元素开始的。名称中的“right”/“left”不是指“从列表的哪一端开始”,而是指折叠功能的关联方式
foldr f acc[x,y,z]
fx(fy(fz acc))
,而具有相同参数的
foldl
f(f(f acc x)y)z
foldl
写起来有点麻烦,因为列表本身就具有内在的右关联性(
[x,y,z]==x:y:z:[]=x:(
)。
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