对“组合者”的好解释(非数学家)

时间:2008-09-18 22:25:40

标签: function lambda combinators y-combinator

任何人都对“组合器”(Y-combinators等和 NOT the company)有一个很好的解释?

我正在寻找一位了解递归和高阶函数的实用程序员,但没有强大的理论或数学背景。

(注意:我说的是these things

8 个答案:

答案 0 :(得分:28)

除非你深入理论,否则你可以考虑Y组合 作为一个功能齐全的技巧,如monads。

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

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

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

> fun()
bla
bla
bla
...

fun可在fun内部访问,因此我们可以轻松调用它。

但是,如果Python不同,fun无法访问,该怎么办? 在fun内?

> 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%正确,但我认为这是一般的想法。)

答案 1 :(得分:21)

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

虽然他(据我所知)没有看到Y-combinator本身,但他确实看过其他组合器,例如:

以及关于can use他们的一些帖子。

答案 2 :(得分:11)

引用维基百科:

  

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

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

这些功能是什么样的,它们用于什么?以下是一些例子:

(f o g)(x) = f(g(x))

此处o是一个组合器,它接收2个函数fg,并返回一个函数作为结果,f的组合为{{1} },即g

组合器可用于隐藏逻辑。假设我们有一个数据类型f o g,其中NumberUndefined可以采用数值NumberUndefined或值Num x,其中Undefined a是{{1} }}。现在我们要为这个新的数字类型构造加法,减法,乘法和除法。语义与x的语义相同,除非Number是输入,输出也必须是Number,当除以数字Undefined时,输出也是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 monad,程序员可以在像Haskell这样的函数式语言中使用它,但我不会去那里。

答案 3 :(得分:7)

组合器具有无自由变量的功能。这意味着,除其他外,组合器不依赖于函数外部的事物,只依赖于函数参数。

使用F#这是我对组合器的理解:

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

在上面的例子中,sum是一个组合子,因为ab都与函数参数绑定。

let sum3 a b c = sum((sum a b) c);;

上述函数不是组合子,因为它使用sum,它不是绑定变量(即它不是来自任何参数)。

我们可以通过简单地将sum函数作为参数之一传递给sum3一个组合器:

let sum3 a b c sumFunc = sumFunc((sumFunc a b) c);;

这种方式sumFunc 绑定,因此整个函数都是组合子。

所以,这是我对组合器的理解。另一方面,它们的重要性仍然让我失望。正如其他人所指出的那样,定点组合子允许表达递归函数而没有explicit递归。即而不是调用自身的recusrsive函数调用作为参数之一传入的lambda。

这是我发现的最容易理解的组合子派生之一:

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

答案 4 :(得分:2)

答案 5 :(得分:1)

这是一个很好的article。 代码示例在方案中,但它们不应该很难遵循。

答案 6 :(得分:1)

我在理论方面很缺乏,但我可以举一个例子来说明我的想象力,这可能对你有所帮助。最简单有趣的组合可能是“测试”。

希望你了解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,则

test计算第二个参数,否则为第三个参数。

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

整个系统可以从几个基本的组合器构建。

(这个例子或多或少地复制了Benjamin C. Pierce的类型和编程语言)

答案 7 :(得分:0)

简而言之,Y组合子是一个更高阶函数,用于实现lambda表达式(匿名函数)的递归。查看Mike Vanier撰写的文章How to Succeed at Recursion Without Really Recursing - 这是我见过的最好的实际解释之一。

另外,扫描SO档案: