haskell的折叠器总是采用双参数lambda吗?

时间:2015-01-12 16:36:09

标签: haskell fold

Haskell newb here

我在haskell中处理这个问题:

(**) Eliminate consecutive duplicates of list elements.
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.

Example:
* (compress '(a a a a b c c a a d e e e e))
(A B C A D E)

解决方案(我必须查找)使用foldr:

compress' :: (Eq a) => [a] -> [a]
compress' xs = foldr (\x acc -> if x == (head acc) then acc else x:acc) [last xs] xs

根据解决方案,此折叠器采用两个参数x和acc。似乎所有折叠者都采用这些参数;这有什么例外吗?像折叠器需要3个或更多?如果没有,这个约定是多余的,公式可以用更少的代码编写吗?

2 个答案:

答案 0 :(得分:16)

foldr采用2个参数的函数,但如果函数具有正确的类型签名,则不会阻止它使用3个参数的函数。

如果我们有一个功能

g :: x -> y -> z -> w

使用

foldr :: (a -> b -> b) -> b -> [a] -> b

我们要将g传递给foldr,然后(a -> b -> b) ~ (x -> y -> z -> w)(其中~是类型相等)。由于->是正确的关联,这意味着我们可以将g的签名写为

x -> y -> (z -> w)

和它的含义是一样的。现在我们已经生成了两个参数的函数,它返回一个参数的函数。为了将其与类型a -> b -> b统一起来,我们只需要排列参数:

a ->   |  x ->
b ->   |  y -> 
b      |  (z -> w)

这意味着b ~ z -> wy ~ b ~ z -> wa ~ x所以g的类型确实必须

g :: x -> (z -> w) -> (z -> w)

言下之意

foldr g :: (z -> w) -> [x] -> (z -> w)

这当然不是不可能的,尽管不太可能。我们的累加器是一个函数,对我而言,这需要使用DiffLists进行演示:

type DiffList a = [a] -> [a]

append :: a -> DiffList a -> DiffList a
append x dl = \xs -> dl xs ++ [x]

reverse' :: [a] -> [a]
reverse' xs = foldr append (const []) xs $ []

请注意,foldr append (const []) xs会返回一个函数,我们将其应用于[]以反转列表。在这种情况下,我们给了一个名为[a] -> [a]的{​​{1}}类型函数的别名,但它与编写的文本没什么不同

DiffList

这是3个参数的函数。

答案 1 :(得分:4)

与haskell中的所有内容一样,您可以查看 types 的内容,以指导您为ghci中的任何功能执行此操作。

看看这个折叠器,我们看到:

Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b

这个稍微抽象的字符串可以用英文写成:

foldr是一个带

的函数

1)具有两个参数的函数,其中一个类型为a,另一个类型为b,并返回类型为b

的类型

2)类型b

的值

3)类型a

的值列表

并返回b

类型的值

其中ab是类型变量(有关它们的详细教程,请参阅here),可以使用您喜欢的任何类型填写。