Function 为什么这些褶皱在头部/尾部停止?

Function 为什么这些褶皱在头部/尾部停止?,function,haskell,functional-programming,fold,Function,Haskell,Functional Programming,Fold,我正在阅读learnyouahaskell.com,目前正在调查褶皱。书中有以下例子: maximum' :: (Ord a) => [a] -> a maximum' = foldr1 (\x acc -> if x > acc then x else acc) reverse' :: [a] -> [a] reverse' = foldl (\acc x -> x : acc) [] product' :: (Num a) =>

我正在阅读learnyouahaskell.com,目前正在调查褶皱。书中有以下例子:

maximum' :: (Ord a) => [a] -> a  
maximum' = foldr1 (\x acc -> if x > acc then x else acc)  

reverse' :: [a] -> [a]  
reverse' = foldl (\acc x -> x : acc) []  

product' :: (Num a) => [a] -> a  
product' = foldr1 (*)  

filter' :: (a -> Bool) -> [a] -> [a]  
filter' p = foldr (\x acc -> if p x then x : acc else acc) []  

head' :: [a] -> a  
head' = foldr1 (\x _ -> x)  

last' :: [a] -> a  
last' = foldl1 (\_ x -> x) 
除了
head'
tail'
,我都懂

我的理解是,二进制函数应该依次应用于累加器和列表中的每个元素,从而遍历所有列表。为什么这会停在头部(或尾部)


我理解
(下划线)的意思是“不管什么”或“我不在乎”,但这怎么会停止浏览所有列表呢?

foldr将两个项目组合在一起—当前的“运行总计”类项目和新项目

(\x\ux->x)
接受新项目并丢弃它,保留原始项目,因此忽略所有剩余项目

让我们扩展一下:

foldr1 (\x _ -> x) [1..100000]
= (\x _ -> x) 1 (foldr (\x _ -> x) [2..100000])
= 1
由于不需要
(foldr(\x\ux->x)[2..100000])
术语,因此不会对其进行求值(这是活动中的延迟求值,或者更确切地说是不活动),因此运行速度很快


使用
(\\ux->x)
,将获取新项目并忽略旧项目-这种情况一直持续到列表末尾,因此您将获得最后一个元素。它没有避开其他的,只是忘记了所有的,除了最后一个

一个更易于理解的名称
(\\ux->x)
表示忽略第一个参数并返回第二个参数。让我们称之为
secondArg

foldl1 (\_ x -> x) [1..4]
= let secondArg = (\_ x -> x) in foldl secondArg 1 [2..4]
= foldl (1 `secondArg` 2) [3..4] 
= foldl ((1 `secondArg` 2) `secondArg` 3) [4]
= foldl (((1 `secondArg` 2) `secondArg` 3) `secondArg` 4) []
= (((1 `secondArg` 2) `secondArg` 3) `secondArg` 4)
= 4

首先让我们看一下
foldr1
的定义:

foldr1 :: (a -> a -> a) -> [a]       -> a
foldr1    f                [x]       =  x
foldr1    f                (x : xs)  =  f x (foldr1 f xs)

然后,考虑函数的调用<代码>头< <代码>,

head' :: [a] -> a  
head' =  foldr1 (\x _ -> x)
对于列表,例如,
[2,3,5]

head' [2, 3, 5]
现在,在
标题的右侧填充“
将给出

foldr1 (\x _ -> x) [2, 3, 5]
回想一下,
[2,3,5]
(2:3:5:[])
的语法糖。因此,
foldr1
定义的第二种情况适用,我们给出

(\x _ -> x) 2 (foldr1 (\x _ -> x) (3 : 5 : [])
现在,减少应用程序会导致
2
绑定到
x
foldr1(\x->x)(3:5:[])
绑定到被忽略的参数
。左侧是lambda抽象的右侧,其中
x
2
替换:

2

请注意,延迟求值使得被忽略的参数
foldr1(\x u->x)(3:5:[])
未被求值,因此,这很有希望回答您的问题,在我们处理完列表的其余部分之前,递归停止。

Haskell的延迟求值不会加快帖子中的
标题的速度吗
foldr1(\x\ux->x)[1..100000000000000]
在GHCi中运行不到一眨眼。