使用文件夹定义追加

时间:2019-06-02 15:35:39

标签: haskell

我已经看到可以通过这种方式在Haskell中定义append函数

append :: [a] -> [a] -> [a]
append = flip (foldr (:))

我正在寻找有关其工作原理的解释。我的主要问题是我不知道foldr如何将列表作为参数。不过,对整个实现进行完整的解释会很好。

3 个答案:

答案 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和两个参数xy,并且像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。对于列表foldrimplemented 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