工人组合词解释

什么是组合子

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

或者这个怎么样: 根据 约翰 · 休斯在他关于 Arrows 的著名论文 “组合器是一个从程序片段中构建程序片段的函数”,这是有利的,因为“ ... 程序员使用组合器自动构造大部分所需的程序,而不是手写每一个细节”。他接着说,mapfilter是这种组合子的两个常见例子。

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

  • 是的
  • K
  • 为什么
  • 其他人从 嘲笑知更鸟(我可能是错的——我没有读过这本书)

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

  • 地图
  • 过滤器
  • 折叠/减少(假设)
  • 任何 > > = ,撰写,fmap? ? ? ?

我对第一个定义不感兴趣——它们不会帮助我编写一个真正的程序(如果你让我相信我错了,那么 + 1)。请帮助我理解第二个定义.我认为 map、 filter 和 reduce 是有用的: 它们允许我在更高的层次上编程——更少的错误,更短更清晰的代码。下面是我关于组合子的一些具体问题:

  1. 还有哪些组合子的例子,比如 map,filter?
  2. 编程语言通常实现哪些组合子?
  3. 组合器如何帮助我设计一个更好的 API?
  4. 如何设计有效的组合器?
  5. 在非函数式语言(比如说 Java)中,组合符类似于什么,或者这些语言用什么来代替组合符?

更新

感谢@C。麦凯恩,我现在对组合子有了一些更好的理解。但有一个问题仍然困扰着我:

使用组合子编写的函数式程序和不使用组合子编写的函数式程序有什么区别?

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

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

17267 次浏览

I'm not interested in the first definition -- those would not help me to write a real program (+1 if you convince me I'm wrong). Please help me understand the second definition. I think map, filter, and reduce are useful: they allow me to program at a higher level -- fewer mistakes, shorter and clearer code.

The two definitions are basically the same thing. The first is based on the formal definition and the examples you give are primitive combinators--the smallest building blocks possible. They can help you to write a real program insofar as, with them, you can build more sophisticated combinators. Think of combinators like S and K as the machine language of a hypothetical "combinatory computer". Actual computers don't work that way, of course, so in practice you'll usually have higher-level operations implemented behind the scenes in other ways, but the conceptual foundation is still a useful tool for understanding the meaning of those higher-level operations.

The second definition you give is more informal and about using more sophisticated combinators, in the form of higher-order functions that combine other functions in various ways. Note that if the basic building blocks are the primitive combinators above, everything built from them is a higher-order function and a combinator as well. In a language where other primitives exist, however, you have a distinction between things that are or are not functions, in which case a combinator is typically defined as a function that manipulates other functions in a general way, rather than operating on any non-function things directly.

What are more examples of combinators such as map, filter?

Far too many to list! Both of those transform a function that describes behavior on a single value into a function that describes behavior on an entire collection. You can also have functions that transform only other functions, such as composing them end-to-end, or splitting and recombining arguments. You can have combinators that turn single-step operations into recursive operations that produce or consume collections. Or all kinds of other things, really.

What combinators do programming languages often implement?

That's going to vary quite a bit. There're relatively few completely generic combinators--mostly the primitive ones mentioned above--so in most cases combinators will have some awareness of any data structures being used (even if those data structures are built out of other combinators anyway), in which case there are typically a handful of "fully generic" combinators and then whatever various specialized forms someone decided to provide. There are a ridiculous number of cases where (suitably generalized versions of) map, fold, and unfold are enough to do almost everything you might want.

How can combinators help me design a better API?

Exactly as you said, by thinking in terms of high-level operations, and the way those interact, instead of low-level details.

Think about the popularity of "for each"-style loops over collections, which let you abstract over the details of enumerating a collection. These are just map/fold operations in most cases, and by making that a combinator (rather than built-in syntax) you can do things such as take two existing loops and directly combine them in multiple ways--nest one inside the other, do one after the other, and so on--by just applying a combinator, rather than juggling a whole bunch of code around.

How do I design effective combinators?

First, think about what operations make sense on whatever data your program uses. Then think about how those operations can be meaningfully combined in generic ways, as well as how operations can be broken down into smaller pieces that are connected back together. The main thing is to work with transformations and operations, not direct actions. When you have a function that just does some complicated bit of functionality in an opaque way and only spits out some sort of pre-digested result, there's not much you can do with that. Leave the final results to the code that uses the combinators--you want things that take you from point A to point B, not things that expect to be the beginning or end of a process.

What are combinators similar to in a non-functional language (say, Java), or what do these languages use in place of combinators?

Ahahahaha. Funny you should ask, because objects are really higher-order thingies in the first place--they have some data, but they also carry around a bunch of operations, and quite a lot of what constitutes good OOP design boils down to "objects should usually act like combinators, not data structures".

So probably the best answer here is that instead of combinator-like things, they use classes with lots of getter and setter methods or public fields, and logic that mostly consists of doing some opaque, predefined action.