理解实现 foldr 和 foldl 的函数
Understanding function which implements foldr and foldl
在某些情况下,我不明白 foldr
和 foldl
是如何在函数中使用的。
这里举几个例子,然后我解释一下为什么我不明白它们:
-- Two implementation of filter and map
map' f = foldr (\x acc -> (f x):acc) []
map'' f xs = foldl (\acc x -> acc ++ [(f x)]) [] xs
filter' f xs = foldr(\x acc -> if(f x) then x:acc else acc) [] xs
filter'' f = foldl(\acc x -> if(f x) then acc++[x] else acc) []
为什么 map''
使用 xs
而不是 map'
? map'
不应该也需要列表理解公式的列表吗?
filter'
与 filter''
的情况相同。
这是一个在排序序列中插入元素的实现:
insert e [] = [e]
insert e (x:xs)
| e > x = x: insert e xs
| otherwise = e:x:xs
sortInsertion xs = foldr insert [] xs
sortInsertion'' xs = foldl (flip insert) [] xs
为什么 insert
的参数在 sortInsertion
([] xs
) 中翻转(空列表和列表)与 insert(e []) 的定义(元素和空列表)
即偏函数应用
map' f = foldr (\x acc -> (f x):acc) []
和
一样
map' f xs = foldr (\x acc -> (f x):acc) [] xs
如果两边省略xs
。
但是,除了这个解释之外,我认为您还需要一本 Haskell 的初学者书籍。考虑 LYAH.
Why does map''
makes the use of xs
but non map'
? Shouldn't map'
need a list for the list comprehension formula as well? Same case for filter'
vs filter''
.
这称为“eta-reduction”,它是一种省略冗余参数名称的常用方法(“无点样式”)。本质上,只要你有一个函数,它的主体只是函数对其参数的应用,你就可以减少参数:
add :: Int -> Int -> Int
add x y = x + y
-- “To add x and y, call (+) on x and y.”
add :: (Int) -> (Int) -> (Int)
add x y = ((+) x) y
-- “To add x, call (+) on x.”
add :: (Int) -> (Int -> Int)
add x = (+) x
-- “To add, call (+).”
add :: (Int -> Int -> Int)
add = (+)
更准确地说,如果您有 f x = g x
,其中 x
没有出现在 g
中,那么您可以写成 f = g
.
一个常见的错误就是想知道为什么 f x = g . h x
不能写成 f = g . h
。它不符合模式,因为 (.)
运算符是 f
主体中的顶级表达式:它实际上是 f x = (.) g (h x)
。您 可以 将其写为 f x = (((.) g) . h) x
,然后使用 ->
的 Functor
实例将其缩减为 f = (.) g . h
或 f = fmap g . h
, 但这不是很可读。
Why are the argument for insert flipped in sortInsertion
foldr
和foldl
的函数参数参数顺序不同:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
或者,使用更详细的类型变量名称:
foldr
:: (Foldable container)
=> (element -> accumulator -> accumulator)
-> accumulator -> container element -> accumulator
foldl
:: (Foldable container)
=> (accumulator -> element -> accumulator)
-> accumulator -> container element -> accumulator
这只是折叠关联方向的助记符:
foldr f z [a, b, c, d]
==
f a (f b (f c (f d z))) -- accumulator on the right (second argument)
foldl f z [a, b, c, d]
==
f (f (f (f z a) b) c) d -- accumulator on the left (first argument)
在某些情况下,我不明白 foldr
和 foldl
是如何在函数中使用的。
这里举几个例子,然后我解释一下为什么我不明白它们:
-- Two implementation of filter and map
map' f = foldr (\x acc -> (f x):acc) []
map'' f xs = foldl (\acc x -> acc ++ [(f x)]) [] xs
filter' f xs = foldr(\x acc -> if(f x) then x:acc else acc) [] xs
filter'' f = foldl(\acc x -> if(f x) then acc++[x] else acc) []
为什么 map''
使用 xs
而不是 map'
? map'
不应该也需要列表理解公式的列表吗?
filter'
与 filter''
的情况相同。
这是一个在排序序列中插入元素的实现:
insert e [] = [e]
insert e (x:xs)
| e > x = x: insert e xs
| otherwise = e:x:xs
sortInsertion xs = foldr insert [] xs
sortInsertion'' xs = foldl (flip insert) [] xs
为什么 insert
的参数在 sortInsertion
([] xs
) 中翻转(空列表和列表)与 insert(e []) 的定义(元素和空列表)
即偏函数应用
map' f = foldr (\x acc -> (f x):acc) []
和
一样map' f xs = foldr (\x acc -> (f x):acc) [] xs
如果两边省略xs
。
但是,除了这个解释之外,我认为您还需要一本 Haskell 的初学者书籍。考虑 LYAH.
Why does
map''
makes the use ofxs
but nonmap'
? Shouldn'tmap'
need a list for the list comprehension formula as well? Same case forfilter'
vsfilter''
.
这称为“eta-reduction”,它是一种省略冗余参数名称的常用方法(“无点样式”)。本质上,只要你有一个函数,它的主体只是函数对其参数的应用,你就可以减少参数:
add :: Int -> Int -> Int
add x y = x + y
-- “To add x and y, call (+) on x and y.”
add :: (Int) -> (Int) -> (Int)
add x y = ((+) x) y
-- “To add x, call (+) on x.”
add :: (Int) -> (Int -> Int)
add x = (+) x
-- “To add, call (+).”
add :: (Int -> Int -> Int)
add = (+)
更准确地说,如果您有 f x = g x
,其中 x
没有出现在 g
中,那么您可以写成 f = g
.
一个常见的错误就是想知道为什么 f x = g . h x
不能写成 f = g . h
。它不符合模式,因为 (.)
运算符是 f
主体中的顶级表达式:它实际上是 f x = (.) g (h x)
。您 可以 将其写为 f x = (((.) g) . h) x
,然后使用 ->
的 Functor
实例将其缩减为 f = (.) g . h
或 f = fmap g . h
, 但这不是很可读。
Why are the argument for insert flipped in
sortInsertion
foldr
和foldl
的函数参数参数顺序不同:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
或者,使用更详细的类型变量名称:
foldr
:: (Foldable container)
=> (element -> accumulator -> accumulator)
-> accumulator -> container element -> accumulator
foldl
:: (Foldable container)
=> (accumulator -> element -> accumulator)
-> accumulator -> container element -> accumulator
这只是折叠关联方向的助记符:
foldr f z [a, b, c, d]
==
f a (f b (f c (f d z))) -- accumulator on the right (second argument)
foldl f z [a, b, c, d]
==
f (f (f (f z a) b) c) d -- accumulator on the left (first argument)