对“组合器”的很好的解释 (对于非数学家)

发布于 2024-07-04 15:52:23 字数 344 浏览 13 评论 0原文

任何人都对“组合器”(Y-组合器等)有很好的解释,并且NOT 公司)?

我正在为了解递归和高阶函数但没有很强的理论或数学背景的实际程序员寻找一个。

(注意:我正在谈论这些事情

Anyone got a good explanation of "combinators" (Y-combinators etc. and NOT the company)?

I'm looking for one for the practical programmer who understands recursion and higher-order functions, but doesn't have a strong theory or math background.

(Note: that I'm talking about these things)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

雨后彩虹 2024-07-11 15:52:23

引用维基百科:

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

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

这些函数是什么样的以及它们的用途是什么? 以下是一些示例:

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

这里 o 是一个组合器,它接受 2 个函数,f 和 g,并返回一个函数作为其结果,由 fg 组成,即 fo g

组合器可用于隐藏逻辑。 假设我们有一个数据类型 NumberUndefined,其中 NumberUndefine 可以采用数值 Num x 或值 Undefined ,其中 x a 是一个数字。 现在我们要为这个新的数字类型构造加法、减法、乘法和除法。 语义与 Number 的语义相同,除非如果 Undefined 是输入,则输出也必须是 Undefined 并且除以数字时0 输出也是未定义

人们可以编写如下乏味的代码:

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)

注意所有关于未定义输入值的逻辑都是相同的。 只有除法做得更多一些。 解决方案是通过使其成为组合器来提取逻辑。

comb (~) Undefined num = Undefined
comb (~) num Undefined = Undefined
comb (~) (Num x) (Num y) = Num (x ~ y)

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

这可以推广到程序员在 Haskell 等函数式语言中使用的所谓的 Maybe monad,但我不会去那里。

Quote Wikipedia:

A combinator is a higher-order function that uses only function application and earlier defined combinators to define a result from its arguments.

Now what does this mean? It means a combinator is a function (output is determined solely by its input) whose input includes a function as an argument.

What do such functions look like and what are they used for? Here are some examples:

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

Here o is a combinator that takes in 2 functions , f and g, and returns a function as its result, the composition of f with g, namely f o g.

Combinators can be used to hide logic. Say we have a data type NumberUndefined, where NumberUndefined can take on a numeric value Num x or a value Undefined, where x a is a Number. Now we want to construct addition, subtraction, multiplication, and division for this new numeric type. The semantics are the same as for those of Number except if Undefined is an input, the output must also be Undefined and when dividing by the number 0 the output is also Undefined.

One could write the tedious code as below:

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)

Notice how the all have the same logic concerning Undefined input values. Only division does a bit more. The solution is to extract out the logic by making it a combinator.

comb (~) Undefined num = Undefined
comb (~) num Undefined = Undefined
comb (~) (Num x) (Num y) = Num (x ~ y)

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

This can be generalized into the so-called Maybe monad that programmers make use of in functional languages like Haskell, but I won't go there.

街道布景 2024-07-11 15:52:23

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

虽然他(据我所知)没有研究 Y 组合器本身,但他确实研究了其他组合器,例如:

以及一些关于如何可以< /a> 使用它们。

Reginald Braithwaite (aka Raganwald) has been writing a great series on combinators in Ruby over at his new blog, homoiconic.

While he doesn't (to my knowledge) look at the Y-combinator itself, he does look at other combinators, for instance:

and a few posts on how you can use them.

梦在夏天 2024-07-11 15:52:23

除非你对理论很深入,否则你可以考虑 Y 组合器
作为一个巧妙的函数技巧,比如 monad。

Monad 允许您链接操作,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%正确,但我认为这是一般的想法。)

Unless you're deeply into theory, you can regard the Y combinator
as a neat trick with functions, like monads.

Monads allow you to chain actions, the Y combinator allows you to
define self-recursive functions.

Python has built-in support for self-recursive functions, so you
can define them without Y:

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

> fun()
bla
bla
bla
...

fun is accessible inside fun itself, so we can easily call it.

But what if Python were different, and fun weren't accessible
inside fun?

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

The solution is to pass fun itself as an argument to fun:

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

And Y makes that possible:

> def Y(f):
>   f(f)

> Y(fun)
bla
bla
bla
...

All it does it call a function with itself as argument.

(I don't know if this definition of Y is 100% correct, but I think it's the general idea.)

小兔几 2024-07-11 15:52:23

这是一篇很好的文章
代码示例在方案中,但它们应该不难理解。

This is a good article.
The code examples are in scheme, but they shouldn't be hard to follow.

蝶…霜飞 2024-07-11 15:52:23

我的理论很短,但我可以给你举一个激发我想象力的例子,这可能对你有帮助。 最简单有趣的组合器可能是“测试”。

希望您知道 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 的《类型和编程语言》中复制而来的)

I'm pretty short on theory, but I can give you an example that sets my imagination aflutter, which may be helpful to you. The simplest interesting combinator is probably "test".

Hope you know Python

tru = lambda x,y: x
fls = lambda x,y: y 

test = lambda l,m,n: l(m,n)

Usage:

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

test evaluates to the second argument if the first argument is true, otherwise the third.

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

Entire systems can be built up from a few basic combinators.

(This example is more or less copied out of Types and Programming Languages by Benjamin C. Pierce)

酸甜透明夹心 2024-07-11 15:52:23

简而言之,Y 组合器是一个高阶函数,用于实现 lambda 表达式(匿名函数)的递归。 查看 Mike Vanier 的文章如何在没有真正递归的情况下成功实现递归 - 这是最实用的文章之一我见过对这件事的解释。

另外,扫描 SO 档案:

Shortly, Y combinator is a higher order function that is used to implement recursion on lambda expressions (anonymous functions). Check the article How to Succeed at Recursion Without Really Recursing by Mike Vanier - it's one of best practical explanation of this matter I've seen.

Also, scan the SO archives:

温柔女人霸气范 2024-07-11 15:52:23

组合器是没有自由变量的函数。 这意味着,除其他外,组合器不依赖于函数外部的事物,仅依赖于函数参数。

使用 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绑定的,因此整个函数是一个组合器。

所以,这就是我对组合器的理解。 另一方面,我仍然不明白它们的意义。 正如其他人指出的那样,定点组合器允许人们在没有显式递归的情况下表达递归函数。 即,递归函数不调用自身,而是调用作为参数之一传入的 lambda。

这是我发现的最容易理解的组合器推导之一:

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

A combinator is function with no free variables. That means, amongst other things, that the combinator does not have dependencies on things outside of the function, only on the function parameters.

Using F# this is my understanding of combinators:

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

In the above case sum is a combinator because both a and b are bound to the function parameters.

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

The above function is not a combinator as it uses sum, which is not a bound variable (i.e. it doesn't come from any of the parameters).

We can make sum3 a combinator by simply passing the sum function as one of the parameters:

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

This way sumFunc is bound and hence the entire function is a combinator.

So, this is my understanding of combinators. Their significance, on the other hand, still escapes me. As others pointed out, fixed point combinators allow one to express a recursive function without explicit recursion. I.e. instead of calling itself the recusrsive function calls lambda that is passed in as one of the arguments.

Here is one of the most understandable combinator derivations that I found:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文