我已经看到可以通过这种方式在Haskell中定义append
函数
append :: [a] -> [a] -> [a]
append = flip (foldr (:))
我正在寻找有关其工作原理的解释。我的主要问题是我不知道foldr
如何将列表作为参数。不过,对整个实现进行完整的解释会很好。
答案 0 :(得分:7)
foldr
需要三个参数:一个累加器函数,一个初始累加器值和一个列表(可折叠)。
foldr (:)
因此还需要两个参数:初始累加器和列表。
这里要做的是巧妙地使用两个列表之一作为初始累加器。
然后,将另一个列表中的每个元素限制在初始列表中;导致另一个列表中的所有元素都附加到初始列表中。
基本上,append [1,2,3] [4,5,6]
等同于foldr (:) [4,5,6] [1,2,3]
,最终会做(1:(2:(3:[4,5,6])))
,结果是[1,2,3,4,5,6]
答案 1 :(得分:3)
flip :: (a -> b -> c) -> b -> a -> c
的实现方式为:
flip :: (a -> b -> c) -> b -> a -> c flip f x y = f y x
因此为它提供了一个函数f
和两个参数x
和y
,并且像f y x
一样应用了这些参数。因此,这意味着append = flip (foldr (:))
的缩写:
append :: [a] -> [a] -> [a]
append xs ys = foldr (:) ys xs
现在,您可以将foldr
视为列表的catamorphsim [wiki]。实际上,对于foldr f z ls
,它将(:)
列表中的缺点ls
替换为f
,并将空白列表[]
替换为z
。对于列表foldr
为implemented as:
foldr :: (a -> b -> b) -> b -> [a] -> b foldr k z = go where go [] = z go (y:ys) = y `k` go ys
因此,对于等于{{1}的foldr (+) 0 [x1, x2, x3]
,等于foldr (+) 0 (x1 : (x2 : (x3 : [])))
或更详细的x1 + (x2 + (x3 + 0))
。
因此对于这里的x1 + x2 + x3 + 0
,具有列表foldr (:) ys
,它等于[x1, x2, x3]
,因此,它等于(x1 : (x2 : (x3 : ys)))
的列表。
答案 2 :(得分:1)
flip f xs ys = f ys xs
,然后
append xs ys = flip (foldr (:)) xs ys
= foldr (:) ys xs
现在,foldr g z xs
将:
中的每个xs
替换为g
,并将[]
中的最后一个xs
替换为{{1 }},我们得到了
z
关于从何处获取列表,它们只是隐式地 。 Haskell允许通过从左侧和右侧删除相同的最后一个参数来缩短定义,如果剩下的不需要的话:
append (x1 : x2 : ... : xn : []) ys = foldr (:) ys xs
-- replace `:` with `:` and `[]` with `ys`:
= (x1 : x2 : ... : xn : ys)
foo x y z = g x x y z
foo x y = g x x y
foo x = g x x
= join g x
foo = join g
不能简单地删除,因为其余的x
需要使用它。但是,在使用g x
对其进行了转换(此处的详细信息以及其工作原理无关紧要)之后,也有可能删除其余的join
。
在您的情况下,参数仅使用一次,并使用x
函数翻转其顺序:
flip