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