我是Haskell的新手,我尝试使用第二个元素的(String)长度过滤一个元组列表,并返回正确的元组(如果有的话)。.
Prelude> let lst = [(a,rr), (b,rr), (c, rrr), (d, rrrr)]
Prelude> filter ((>4).(length snd)) lst
[d, rrrr)]
尝试执行时出错,该长度包含太多参数。
有人可以帮助我吗?非常感谢!
答案 0 :(得分:2)
filter ((>4).(length snd)) lst
您似乎对此有正确的想法,但是如您所知,它无法编译。尽管在尝试时,该错误与您提到的关于length
的参数过多的错误不同-您在此处给了它一个参数,它是正确的数字。但是,您提供给它的参数是一个函数(snd
,它为您提供了对的第二个元素),并且它需要一个列表-由于无法将函数视为列表,因此编译器认为这毫无意义。 (即使这不是问题,length snd
也会产生一个Int
,并且您不能将其用作.
运算符的参数,该运算符在任一端都需要一个函数。这是GHC在我尝试运行您的代码时实际上抱怨的:Couldn't match expected type '([Char], [Char]) -> Integer' with actual type 'Int' In the second argument of '(.)', namely '(length snd)'
)
@WillemVanOnsem已经向您展示了如何修复它,所以让我们看一下。确实与您的非常相似:
filter ((>4) . length . snd)) lst
您似乎已经知道,.
运算符首先将功能应用到其右侧,然后将其左侧应用到结果。因此,表达式(>4) . length . snd
的意思是,给定一对,取第二个元素,然后取其长度(假定它是一个列表,否则将不编译),然后检查结果数是否大于4或不。换句话说,(>4) . length . snd)
是类型(a, [b]) -> Bool
的谓词,它告诉您该对第二个插槽中的列表是否包含4个以上的元素。 [术语“谓词”仅表示任何返回Bool
的函数-它是一种测试,适用于您感兴趣的类型的元素,如filter
和许多相关函数中使用的。]当然正是您的目标。
因此,总而言之,答案和正确答案之间的唯一区别是length snd
之间的区别(赋予snd
函数作为length
的参数,这毫无意义),和length . snd
(通过首先将snd
然后应用于结果length
来给出的功能)。它们看起来很相似,但实际上含义却截然不同。
我敢肯定,通过更多的练习,您将能够自行解决此类问题,并了解GHC在给您带来编译错误时会告诉您什么。
(PS:您的代码实际上首先失败,因为a
,rr
等是您没有绑定任何值的变量。我假设它们都是为了是字符串,尤其是在您引用r..r
值的长度时-在这种情况下,它们需要用双引号引起来:("a", "rr")
等。
答案 1 :(得分:0)
此修复程序很完善,但是仍然存在必须知道函数中最长的字符串长度才能匹配或超过它的问题。如果您不知道最长的字段长度并且无法在函数中编码怎么办? lf
函数吐出最长字符串的长度。我确实认为filter谓词中的lambda更容易理解。
lf必须跟踪到目前为止最长的字符串,以便它不能传递元组,而只能传递单个值。
ls = [('a',"rr"), ('b',"rr"), ('c', "rrr"), ('d', "rrrr")]
lf = (\a b -> if (length $ snd b) > a then (length $ snd b) else a)
filter (\t -> (length $ snd t) == (foldl lf 0 ls)) ls
[('d',“ rrrr”)]