[英]Defining foldl in terms of foldr
myFoldl :: (a -> b -> a) -> a -> [b] -> a
myFoldl f z xs = foldr step id xs z
where step x g a = g (f a x)
I am currently reading a book on Haskell. 我正在读一本关于Haskell的书。 And in it, it wrote its own version of the foldl function, but in terms of foldr. 在其中,它编写了自己的foldl函数版本,但就foldr而言。 I do not follow. 我不跟随。
The thing will be become obvious when to expand the expression of foldr step id xs z
: 当扩展foldr step id xs z
的表达式时,事情将变得明显:
As Adam Smith said in the comments: 正如亚当·斯密在评论中所说:
foldr step id xs z = (foldr step id xs) z foldr step id xs z =(foldr step id xs)z
Consider foldr step id xs
firstly 首先考虑foldr step id xs
foldr step id xs
= x1 `step` (foldr step id xs1)
= x1 `step` (x2 `step` (foldr step id xs2))
...
= x1 `step` (x2 `step` ... (xn `step` (foldr step id []))...)
= x1 `step` (x2 `step` ... (xn `step` id)...)
where 哪里
xs = (x1:xs1)
xs1 = (x2:xs2), xs = (x1:x2:xs2)
....
xsn = (xn:[]), xs = (x1:x2...xsn) respectively
Now, apply above function with argument z, ie 现在,将上面的函数应用于参数z,即
(x1 `step` (x2 `step` ... (xn `step` id)...)) z
and let 然后让
g = (x2 `step` ... (xn `step` id)...)
gives 给
(x1 `step` g) z
ie 即
(step x1 g) z
and now apply the where part of foldl: 现在应用foldl的where部分:
where step xga = g (fax) 其中步骤xga = g(传真)
gives 给
(step x1 g) z = step x1 g z = g (step z x1)
where 哪里
g (step z x1) = (x2 `step` (x3 step ... (xn `step` id)...) (step z x1)
let 让
g' = (x3 step ... (xn `step` id)...)
gives 给
(x2 `step` g') (step z x1)
= step x2 g' (step z x1)
= g' (step (step z x1) x2))
= (x3 step ... (xn `step` id)...) (step (step z x1) x2))
repeats the same steps, finally we have, 重复相同的步骤,最后我们有,
(xn `step` id) (step ....(step (step z x1) x2)....)
= step xn id (step ....(step (step z x1) x2)....)
= id (step (step ....(step (step z x1) x2)....) xn)
= (step (step ....(step (step z x1) x2)....) xn)
= foldl step z xs
and now, it is obvious that why use id function. 现在,很明显为什么要使用id函数。 finally, see why 最后,看看为什么
foldl step z xs = (step (step ....(step (step z x1) x2)....) xn)
initial case: 初始案例:
foldl step z' [] = z'
recursive case: 递归案例:
foldl step z (x1:xs1)
= foldl step (step z x1) xs1
= foldl step (step (step z x1) x2) xs2
...
= foldl step (step (step ....(step (step z x1) x2)....) xn) []
= (step (step ....(step (step z x1) x2)....) xn)
where 哪里
z' = (step (step ....(step (step z x1) x2)....) xn) in initial case
Just same as above. 和上面一样。
As Adam Smith says in the comments, there are only three arguments to foldr
. 正如亚当·斯密在评论中所说, foldr
只有三个论点。 The line in question gets parsed like this: 有问题的行被解析如下:
myFoldl f z xs = (foldr step id xs) z
There are other implicit brackets too of course, but these are the important ones. 当然还有其他隐含的括号,但这些是重要的。
Here is a rewrite with the type annotations, assuming scoped type variables (ie a
and b
mean the same types throughout this definition). 这是一个带有类型注释的重写,假设作用域类型变量(即a
和b
在整个定义中表示相同的类型)。
myFoldl :: (a -> b -> a) -> a -> [b] -> a
myFoldl f z xs = goFold z
where
goFold :: a -> a
goFold = foldr step id xs
step :: b -> (a -> a) -> (a -> a) -- Last brackets are redundant
step x g a = g (f a x)
I've moved the foldr
invocation into a separate value goFold
so you can see its type and how it gets applied to the z
value. 我已经将foldr
调用移动到单独的值goFold
因此您可以看到它的类型以及它如何应用于z
值。 The step
function accumulates the b
values into a function of type (a -> a)
. step
函数将b
值累加到类型(a -> a)
的函数中。 Each b
value processed by goFold
adds an extra one of these. goFold
处理的每个b
值goFold
额外添加其中一个。 The "zero" for functions is of course id
from the Prelude: 函数的“零”当然是来自Prelude的id
:
id :: a -> a
id x = x
The ->
function operator in the types is right associative, so the last pair of brackets in the step
type are redundant. 类型中的->
function运算符是右关联的,因此step
类型中的最后一对括号是多余的。 But I've written it like that because it higlights the way in which step
is being used; 但我这样写的是因为它突出了使用step
的方式; it takes a value and a function and returns a new function. 它需要一个值和一个函数并返回一个新函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.