这是我学习Haskell的第二天,我被一个问题严重困扰了。 我试图解决99 Haskell questions中的第八个问题 问题是编写一个名为“compress”的函数,其工作原理如下:
>compress "aaaabbbbccccddddd"
"abcd"
>compress [1,1,1,1,2,3,4,4,4,4]
[1,2,3,4]
这就是我写的:
compress :: (Eq a) => [a] -> [a]
compress [] = []
compress x = filter ( (head x) `notElem` ( compress $ tail x ) ) x
编译说:
无法匹配预期类型
a -> Bool' with actual type
Bool'
在compress
中,我试图以递归方式从头到尾拾取新元素。 (比如回溯也许?)
我的算法错了吗?
有没有其他方式以更易读的方式实现算法?
(比如:在哪里放括号?或$
)
有人可以帮助我吗? 非常感谢。
感谢Lubomir的帮助,我通过以下方式纠正了我的代码:
compress'(x:xs)= x:compress'(dropWhile(== x)xs)
它有效!
谢谢大家,我感到被宠坏了! 你们真好!
我会继续学习Haskell!
答案 0 :(得分:8)
是否有更可读的方法来实现算法 方式是什么?
是
import Data.List
compress :: Eq a => [a] -> [a]
compress = map head . group
map head . group
基本上是\xs -> map head (group xs)
。 group xs
将创建一个列表列表,所有相等的连续元素在列表中组合在一起。然后,map head
会根据需要将这些列表的head
丢弃,然后根据需要将其余列入其中。
答案 1 :(得分:4)
该算法基本上没问题,但它没有进行类型检查。 filter
的第一个参数应该是类型a -> Bool
的函数 - 对于列表的元素,它应该告诉您是否将其抛出。你拥有的是一个Bool
值。
可以使用不同的模式更好地实现函数的第二部分。这样您就可以放弃head
和tail
函数。
compress [] = []
compress (x:xs) = x : compress (filter (/= x) xs)
此模式将x
绑定到列表的第一个元素,xs
是列表的尾部。该函数应在结果中包含x
,并在已过滤的xs
(从x
中删除)中递归调用自身。
编辑:此功能不会执行问题请求。只应删除连续的重复项。这可以通过使用dropWhile
而不是filter
来修复,并稍微修改谓词函数。
答案 2 :(得分:2)
检查过滤器的签名:
Prelude> :t filter
filter :: (a -> Bool) -> [a] -> [a]
请注意,第一个参数必须是函数。现在检查paranthesis中表达式的类型。
Prelude> :t notElem
notElem :: Eq a => a -> [a] -> Bool
因此,notElem a b
将返回Bool
类型的值。
注意:我认为您可能误解了问题陈述。 aaabbbaaa
的预期输出是多少?
我认为它应该是aba
,因为问题被陈述为
消除连续重复的列表元素。
(强调我的)。