“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
是一个组合函数,它接受两个函数f
和g
,并返回一个函数作为其结果, 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)
注意所有人都有相同的逻辑关于Undefined
input值。 只有部门多一点。 解决方法是通过使其成为一个组合器来提取逻辑。
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是一个组合因为a
和b
都绑定到函数参数。
let sum3 abc = sum((sum ab) c);;
上面的函数不是一个组合因为它使用sum
,它不是一个绑定variables(即它不是来自任何参数)。
我们可以通过简单地将sum函数作为参数之一来使sum3成为一个combinator:
let sum3 abc sumFunc = sumFunc((sumFunc ab) c);;
这样sumFunc
被绑定 ,因此整个函数是一个组合器。
所以,这是我对combinators的理解。 另一方面,他们的意义仍然逃避我。 正如其他人指出的那样,定点组合器允许用户expression一个recursion函数,而不需要explicit
recursion。 也就是说,而不是调用自己recusrsive函数调用作为参数之一传入的lambda。
下面是我发现的最容易理解的combinator派生之一:
这看起来很好: http : //www.catonmat.net/blog/derivation-of-ycombinator/
我在理论上很短缺,但我可以给你一个例子,使我的想象力变得混乱,这可能对你有帮助。 最简单的有趣的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实例