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个或更多?如果没有,这个约定是多余的,公式可以用更少的代码编写吗?
答案 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 -> w
,y ~ b ~ z -> w
和a ~ 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
其中a
和b
是类型变量(有关它们的详细教程,请参阅here),可以使用您喜欢的任何类型填写。