【问题标题】:Cannot remove an argument (Point-free style Haskell)无法删除参数(无点样式 Haskell)
【发布时间】:2016-02-09 05:43:29
【问题描述】:

我在删除此函数中的参数“e”时遇到问题:

numocc e = map length . (map . filter . (==)) e

该函数检查二维列表(列表中的列表)内元素的出现次数。所以你这样称呼它:

numocc 1 [[1, 2], [2, 3, 2, 1, 1], [3]]

结果:[1,2,0]

参数 e 位于等号两侧的最右侧,并且不包含在任何参数中。因此,我应该能够将其删除以获得无点功能:

numocc = map length . (map . filter . (==))

但是我得到了这个错误:

应用程序中的类型错误 表达式:地图长度。地图 。筛选 。 (==) 术语:地图长度 类型:[[b]] -> [Int] 不匹配:([[a]] -> [[a]]) -> [Int]

这里有什么问题?谢谢。

【问题讨论】:

  • 当您在列表中测试函数 numocc 时,它也会产生错误。你过滤等于但等于什么?
  • @Zacharie007 对不起,我应该澄清一下,这个函数计算二维列表中元素的出现次数。所以你这样称呼它:numocc 1 [[1, 2], [2, 3, 2, 1, 1], [3]]

标签: haskell functional-programming


【解决方案1】:

你的原始函数被解析为

numocc e = (map length) . ((map . filter . (==)) e)

因此,您不能只删除 e,因为它在技术上并未出现在定义的末尾。但是,如果您定义运算符

(.:) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)
(.:) = (.) . (.)

那么你可以写成

numocc = map length .: (map . filter . (==))

map . filter . (==) 上的括号是必需的,因为由于固定性规则,您不能混合使用 ..:

但是,此时您只是让这个函数更难阅读和维护。最好将其分解为更小的部分并引入一些中间名称,同时添加正确的类型签名并为函数起一个更好的名称:

numOccurrences :: Eq a => a -> [a] -> Int
numOccurrences valueToCount values = length (filter (== valueToCount) values)

numOccurrencesInSublists :: Eq a => a -> [[a]] -> [Int]
numOccurrencesInSublists valueToCount = map (numOccurrences valueToCount)

这更具可读性,不依赖于花哨的运算符,并且更清楚地表达了您的意图。由于在单个列表中计数的情况是一个单独的函数,因此您现在也可以在其他地方使用它。

请记住,优雅的代码不是让它尽可能短,而是让它尽可能清晰。描述性名称(不一定是长名称)、明确的参数和小的、可组合的单元是最好的。

【讨论】:

  • 谢谢!但是有没有其他方法可以做到这一点,而不引入新的运营商?它使函数看起来更加混乱。
  • @VladyslavBabych 检查我的编辑。我还确保澄清第一个代码块中的解析。基本上,不要尝试使用许多花哨的运算符,需要发明更多的运算符才能有效地使用它们。括号通常是最简单和最易读的解决方案,在 99% 的情况下,使用显式参数优于无点表示法。
  • @bheklir 我将接受这个答案,但是这个函数是用于学习目的(大学),并且任务表明我应该以无点风格定义它。但是您的 cmets 仍然非常有帮助,谢谢!如我所见,如果不引入新的运算符,就不可能使其无点。
  • @VladyslavBabych 好吧,这不是不可能,只是方便。 There are several ways to accomplish it,但我不建议在实际代码中使用任何这些
猜你喜欢
  • 1970-01-01
  • 2012-03-14
  • 1970-01-01
  • 2019-10-17
  • 1970-01-01
  • 1970-01-01
  • 2011-11-03
  • 1970-01-01
  • 2019-01-21
相关资源
最近更新 更多