工人的组合器说明


93

什么是组合器?

“没有自由变量的函数或定义”(在SO上定义)吗?

还是这样呢?据约翰·休斯John Hughes)在他关于箭头的著名论文中所说,“组合器是从程序片段中构建程序片段的函数”,这是有优势的,因为“ ...使用组合器的程序员构造了许多所需的自动编程,而不是手工编写每个细节”。他继续说mapfilter是这样的组合子的两个常见的例子。

一些符合第一个定义的组合器:

一些符合第二个定义的组合器:

  • 地图
  • 过滤
  • 折叠/减少(大概)
  • >> =,compose,fmap ?????中的任何一个

我对第一个定义不感兴趣-那些定义不会帮助我编写一个真实的程序(如果您确信我错了,则为+1)。 请帮助我理解第二个定义。我认为map,filter和reduce很有用:它们使我可以进行更高级别的编程-错误更少,代码更短,更清晰。以下是一些有关组合器的具体问题:

  1. 还有哪些组合器示例,例如地图,过滤器?
  2. 编程语言通常实现哪些组合器?
  3. 组合器如何帮助我设计更好的API?
  4. 如何设计有效的组合器?
  5. 与非功能语言(例如Java)中的组合器有什么相似之处,或者这些语言代替组合器使用什么?

更新资料

感谢@CA McCann,现在我对组合器有了更好的了解。但是一个问题仍然是我的症结所在:

使用大量使用组合器编写的功能程序与不使用组合器编写的功能程序有什么区别?

我怀疑答案是,繁重的组合版本更短,更清晰,更通用,但是如果可能的话,我希望进行更深入的讨论。

我还在寻找更多fold常见编程语言中的复杂组合器的示例和解释(即比复杂)。


4
我考虑使用map / filter / fold 高阶函数,并且一直使用它们。我仍然不知道什么是组合器。

1
@pst-我会在5天前达成一致,但现在我不能与John Hughes争辩
Matt Fenwick

Answers:


93

我对第一个定义不感兴趣-那些定义不会帮助我编写一个真实的程序(如果您确信我错了,则为+1)。请帮助我理解第二个定义。我认为map,filter和reduce很有用:它们使我可以进行更高级别的编程-错误更少,代码更短,更清晰。

这两个定义基本上是同一件事。第一个基于形式定义,您提供的示例是原始组合器 -可能的最小构建块。它们可以帮助您编写一个真正的程序,因为您可以使用它们构建更复杂的组合器。将诸如S和K之类的组合器视为一种假设的“组合计算机”的机器语言。当然,实际的计算机不会那样工作,因此在实践中,通常您会在幕后以其他方式实现更高级别的操作,但是概念基础仍然是了解这些更高级别含义的有用工具操作。

您给出的第二个定义是非正式的,是关于使用更复杂的组合器的,其形式是高阶函数,这些函数以各种方式组合了其他函数。请注意,如果基本构建块是上面的原始组合器,则从它们构建的所有内容都是高阶函数和组合器。但是,在存在其他原语的语言中,您会区分是功能还是非功能的事物,在这种情况下,组合器通常被定义为以一般方式操纵其他功能的功能,而不是对任何非功能进行操作的功能。直接发挥作用。

还有哪些组合器示例,例如地图,过滤器?

太多了!两者都将描述单个值行为的函数转换为描述整个集合行为的函数。您还可以具有转换其他功能的功能,例如端到端组成它们,或者拆分和重新组合参数。您可以具有将单步操作转换为产生或使用集合的递归操作的组合器。或其他各种东西,真的。

编程语言通常实现哪些组合器?

这将有很大的不同。完全通用的组合器相对较少(大多数是上面提到的原始组合器),因此在大多数情况下,组合器将对所使用的任何数据结构有所了解(即使这些数据结构仍然由其他组合器构建而成),其中在这种情况下,通常会有少数“完全通用”的组合器,然后有人决定提供各种专业形式。在许多情况下,映射,折叠和展开(适当的通用版本)足以完成几乎所有您想要的事情。

组合器如何帮助我设计更好的API?

就像您所说的那样,通过考虑高级操作及其交互方式,而不是低级细节来进行思考。

考虑一下“为每个”样式的循环在集合中的流行程度,它使您可以抽象出枚举集合的细节。在大多数情况下,这些操作只是映射/折叠操作,通过使用组合器(而不是内置语法),您可以执行以下操作,例如采用两个现有循环并以多种方式直接将它们组合在一起-彼此嵌套,一个接一个地执行,依此类推-仅应用组合器,而不是四处乱码。

如何设计有效的组合器?

首先,考虑对程序使用的任何数据有意义的操作。然后考虑如何以通用方式有意义地组合这些操作,以及如何将操作分解为较小的部分并重新连接在一起。最主要的是要进行转换操作,而不是直接行动。当您拥有一个仅以不透明的方式执行某些复杂功能并且仅吐出某种预先消化结果的函数时,您将无能为力。将最终结果留给使用组合器的代码-您想要使您从A点到B点的东西,而不是希望成为过程开始或结束的东西。

与非功能语言(例如Java)中的组合器有什么相似之处,或者这些语言代替组合器使用什么?

啊哈哈哈哈 有趣的是,您应该问,因为对象首先是真正的高阶对象-它们具有一些数据,但是它们也进行了很多操作,并且构成良好的OOP设计的很多东西都归结为“对象应该通常就像组合器,而不是数据结构。”

因此,最好的答案可能是,它们使用具有大量getter和setter方法或公共字段的类,而不是类似组合器的类,并且逻辑主要由执行一些不透明的预定义动作组成。


好答案!让我们看看我是否理解它-组合器不是特殊的,而是构建可维护软件系统必不可少的一部分?在您的帖子中,我仍在尝试消化休斯的“程序片段”声明。
马特·芬威克

@Matt Fenwick:我很确定他只是用“程序片段”来表示我正在谈论的那种转换/操作,尤其是在谈论“箭头”时,它更加强调了这种方法。而且,我不会说的是确切地构建可维护的系统,而是构建高度模块化并以特定方式分离的系统,从而带来好处。
CA McCann

您是否知道任何有用的资源来阅读组合器的实际用法?谢谢一群!
马特·芬威克

@Matt Fenwick:对不起,我没有什么特别的。但是,对于以非常实用的风格编写的程序来说,这往往是一种自然的方法,因此,只需花一些时间来大力鼓励使用该语言的语言(例如,Haskell或Clojure),然后看看用这种语言编写的干净而惯用的代码,是一种感受风格的不错方法。
CA McCann
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.