将表达式转换为pointfree风格(Haskell)

10

我写了这段代码,现在需要将其重写为pointfree风格:

num_of_occ ele list = length(filter(==ele)list) 

于是我做了这个:

num_of_occ ele = length . filter((==)ele)

它有效。然后我做了这个:

num_of_occ = length . filter . (==)

而且它并没有告诉我我思路中哪里出了问题?


请参见“三节定律”(https://dev59.com/JmrWa4cB1Zd3GeqP8jyU#13147064)。 - Will Ness
1个回答

18

这是一个常见的错误。以下是解决方法:

num_of_occ = (length .) . filter . (==)

这与您的函数接受参数的数量有关。函数组合 (.) 操作符适用于只接受一个参数的函数,您需要将其应用两次 (f .) . 才能使其适用于接受两个参数的函数。

实际上,在 Hackage 上有一个程序可以自动将代码片段转换为无点编程样式,如果您想尝试一下。

$ cabal install pointfree
$ pointfree 'num_of_occ ele list = length (filter (== ele) list)'
num_of_occ = (length .) . filter . (==)

如已指出,这需要类型签名才能正常工作。出于提高 Haskell 性能的目的,这个限制相对单调但比较不明显。您可以打开 NoMonomorphismRestriction 扩展,或添加一个类型签名:

num_of_occ :: Eq a => a -> [a] -> Int
num_of_occ = (length .) . filter . (==)

嗯...这个也返回了一个错误。a.hs:1:31: 由于使用了“==”,没有实例可以匹配 (Eq a0) - ciembor
我正在测试GHCI,版本为7.6.1。 - ciembor
这就是单态限制。添加类型签名或使用-XNoMonomorphismRestriction - shachaf
修正了打字错误 Eq a ->。应该是 Eq a => - Will Ness

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接