“Combinators”的好解释(非math家)

任何人都可以很好的解释“组合器”(Y-combinators等,而不是公司)

我正在寻找一个懂得recursion和高阶函数的实用程序员,但是没有很强的理论和math背景。

(请注意,我正在谈论这些事情: http : //en.wikipedia.org/wiki/Y_combinator )

除非你深入理论,否则你可以把Y组合子视为一个function单调的巧妙手段。

Monads允许你链接动作,Y组合器允许你定义自recursion函数。

Python内置了对自recursion函数的支持,所以你可以在没有Y的情况下定义它们:

> def fun(): > print "bla" > fun() > fun() bla bla bla ... 

fun本身就是fun ,所以我们可以很容易的打电话给它。

但是如果Python是不同的,那么fun是不是可以在里面find的呢?

 > def fun(): > print "bla" > # what to do here? (cannot call fun!) 

解决的办法是把fun本身作为一个参数来传递给fun

 > def fun(arg): # fun receives itself as argument > print "bla" > arg(arg) # to recur, fun calls itself, and passes itself along 

而且Y可以做到这一点:

 > def Y(f): > f(f) > Y(fun) bla bla bla ... 

它所做的只是把自己作为参数来调用一个函数。

(我不知道这个Y的定义是否100%正确,但我认为这是一般的想法。)

Reginald Braithwaite(又名Raganwald)在他的新博客( homoiconic )上撰写了一篇关于Ruby中combinators的精彩系列。

虽然他不知道(据我所知)看着Y-combinator本身,但他确实看着其他的combinators,例如:

  • 茶隼
  • 鹅口疮
  • 红衣主教
  • 红隼
  • 其他古怪的鸟类

以及几个关于如何使用它们的文章。

报价维基百科:

组合器是一个高阶函数,它只使用函数应用程序和较早定义的组合器来定义其参数的结果。

现在这是什么意思? 这意味着一个组合函数是一个函数(输出仅由其input决定),其input包含一个函数作为参数。

这些function是什么样子的?它们用于什么? 这里有些例子:

(fog)(x) = f(g(x))

这里o是一个组合函数,它接受两个函数fg ,并返回一个函数作为其结果, f的组成是g ,即fog

组合器可以用来隐藏逻辑。 假设我们有一个数据typesNumberUndefined ,其中NumberUndefined可以取一个数字值Num x或一个值Undefined ,其中x a是一个Number 。 现在我们要为这个新的数字types构造加法,减法,乘法和除法。 除了Undefined是input外,语义与Number相同,输出也必须是Undefined ,除以数字0 ,输出也是Undefined

人们可以编写如下繁琐的代码:

 Undefined +' num = Undefined num +' Undefined = Undefined (Num x) +' (Num y) = Num (x + y) Undefined -' num = Undefined num -' Undefined = Undefined (Num x) -' (Num y) = Num (x - y) Undefined *' num = Undefined num *' Undefined = Undefined (Num x) *' (Num y) = Num (x * y) Undefined /' num = Undefined num /' Undefined = Undefined (Num x) /' (Num y) = if y == 0 then Undefined else Num (x / y) 

注意所有人都有相同的逻辑关于Undefinedinput值。 只有部门多一点。 解决方法是通过使其成为一个组合器来提取逻辑。

 comb (~) Undefined num = Undefined comb (~) num Undefined = Undefined comb (~) (Num x) (Num y) = Num (x ~ y) x +' y = comb (+) xy x -' y = comb (-) xy x *' y = comb (*) xy x /' y = if y == Num 0 then Undefined else comb (/) xy 

这可以概括为所谓的Maybe monad,程序员可以像Haskell那样使用函数式语言,但是我不会去那里。

组合器是没有自由variables的函数。 这意味着除其他外,组合器不依赖于函数之外的东西,而仅仅依赖于函数参数。

使用F#这是我对combinators的理解:

 let sum ab = a + b;; //sum function (lambda) 

在上述情况下,sum是一个组合因为ab都绑定到函数参数。

 let sum3 abc = sum((sum ab) c);; 

上面的函数不是一个组合因为它使用sum ,它不是一个绑定variables(即它不是来自任何参数)。

我们可以通过简单地将sum函数作为参数之一来使sum3成为一个combinator:

 let sum3 abc sumFunc = sumFunc((sumFunc ab) c);; 

这样sumFunc绑定 ,因此整个函数是一个组合器。

所以,这是我对combinators的理解。 另一方面,他们的意义仍然逃避我。 正如其他人指出的那样,定点组合器允许用户expression一个recursion函数,而不需要explicitrecursion。 也就是说,而不是调用自己recusrsive函数调用作为参数之一传入的lambda。

下面是我发现的最容易理解的combinator派生之一:

http://mvanier.livejournal.com/2897.html

这看起来很好: http : //www.catonmat.net/blog/derivation-of-ycombinator/

这是一篇好文章:

http://www.dreamsongs.com/NewFiles/WhyOfY.pdf

代码示例在计划中,但不应该难以遵循。

我在理论上很短缺,但我可以给你一个例子,使我的想象力变得混乱,这可能对你有帮助。 最简单的有趣的combinator可能是“testing”。

希望你了解Python

 tru = lambda x,y: x fls = lambda x,y: y test = lambda l,m,n: l(m,n) 

用法:

 >>> test(tru,"goto loop","break") 'goto loop' >>> test(fls,"goto loop","break") 'break' 

如果第一个参数为true,则testing评估为第二个参数,否则为第三个参数。

 >>> x = tru >>> test(x,"goto loop","break") 'goto loop' 

整个系统可以由几个基本的组合器构build。

(这个例子或多或less地被Benjamin C. Pierce从types和编程语言中拷贝出来)

简而言之,Y combinator是一个高阶函数,用于实现lambdaexpression式(匿名函数)的recursion。 检查文章如何在recursion成功没有真正recursion迈克Vanier – 这是我见过的这个问题的最好的实际解释之一。

另外,扫描SO档案:

  • 什么是y-组合器?
  • Y-Combinator实例