|
|
1
189
如果你已经准备好长期阅读, Mike Vanier has a great explanation . 长话短说,它允许您在不一定支持递归的语言中实现递归。 |
|
|
2
276
Y组合器是一个“函数”(在其他函数上操作的函数),当您不能从内部引用函数时,它启用递归。在计算机科学理论中 推广递归 抽象其实现,从而将其与相关函数的实际工作分离。递归函数不需要编译时名称的好处有点额外。=) 这适用于支持的语言 lambda functions . 这个 expression -羔羊的本源性通常意味着它们不能用名字来称呼自己。通过声明变量、引用变量、然后为其分配lambda来完成自引用循环来解决这个问题是脆弱的。可以复制lambda变量,并重新分配原始变量,这会中断自引用。 Y组合器在 static-typed 语言(其中 procedural languages 通常是),因为通常类型限制要求在编译时知道所讨论函数的参数数量。这意味着必须为需要使用的任何参数计数编写一个Y组合器。 下面是一个如何使用和工作的Y组合器的例子,在C。 使用Y组合器涉及一种构造递归函数的“不寻常”方法。首先,您必须将函数编写为一段调用预先存在的函数的代码,而不是其本身:
然后将其转换为一个函数,该函数接受一个函数来调用,并返回一个这样做的函数。这被称为函数,因为它接受一个函数,并用它执行一个操作,从而产生另一个函数。
现在您有了一个函数,它接受一个函数,并返回另一个看起来像阶乘的函数,但是它不调用本身,而是调用传递到外部函数的参数。你如何使它成为阶乘?将内部函数传递给自身。Y组合器通过成为一个具有永久名称的函数来实现这一点,该函数可以引入递归。
与factorial调用本身不同,factorial调用factorial生成器(通过递归调用y-combinator返回)。根据t的当前值,从生成器返回的函数将使用t-1再次调用生成器,或者只返回1,终止递归。 它既复杂又神秘,但在运行时都会被淘汰,其工作的关键是“延迟执行”,以及将递归分解为跨两个函数。内部f是 作为参数传递 ,在下一个迭代中调用, 仅在必要时 . |
|
|
3
96
我把这个从 http://www.mail-archive.com/boston-pm@mail.pm.org/msg02716.html 这是我几年前写的一个解释。 在本例中,我将使用JavaScript,但许多其他语言也可以使用。 我们的目标是能够编写1的递归函数 变量仅使用1个变量和no的函数 任务、按名称定义事物等(为什么这是我们的 目标是另一个问题,让我们把它作为 我们面临的挑战。)似乎不可能,嗯?AS 例如,让我们实现阶乘。 第一步是说如果我们 有点作弊。使用2个变量的函数和 我们至少可以避免使用 用于设置递归的赋值。
现在让我们看看我们能不能少作弊。首先,我们使用 任务,但我们不需要。我们只需要写x和 Y内联。
但是我们用两个变量的函数得到一个1的函数 变量。我们能修好吗?好吧,一个聪明人 哈斯克尔咖喱有一个巧妙的技巧,如果你有好的更高的订单 函数,那么您只需要1个变量的函数。这个 证明您可以从2的函数(或 一般情况下)变量变为1个纯 像这样的机械文本转换:
哪里。。。保持不变。(这个把戏叫 以发明者的名字命名。语言haskell也是 以哈斯克尔咖喱命名。把它放在无用的琐事下。) 现在,只要在任何地方应用这个转换,我们就会 我们的最终版本。
你可以试试看。alert()返回,将其绑定到一个按钮,无论什么。 该代码不使用 2个变量的赋值、声明或函数。(但是 试图追踪它是如何工作的,很可能会让你头晕目眩。 在不进行推导的情况下,只需稍微重新格式化即可。 将导致代码被混淆。) 可以将递归定义factorial的4行替换为 您想要的任何其他递归函数。 |
|
|
4
79
我想知道从地上建这个有没有用。让我们看看。下面是一个基本的递归阶乘函数:
让我们重构并创建一个名为
这有点奇怪,但没什么问题。我们只是在每一步生成一个新的阶乘函数。
这个阶段的递归仍然相当明确。这个
很好,但是
现在,而不是打电话
我们现在可以摆脱
唯一仍被引用的外部名称是
|
|
|
5
47
上面的大多数答案都描述了Y组合器 是 但不是什么 对于 . Fixed point combinators 用来表示 lambda calculus 是 turing complete . 这是计算理论中的一个重要结果,为理论计算提供了理论基础。 functional programming . 研究固定点组合器也帮助我真正理解函数编程。不过,在实际的编程中,我从未发现它们有任何用处。 |
|
|
6
23
Y型组合器 JavaScript :
编辑 : 我从代码方面学到了很多东西,但是如果没有背景知识,这个有点难以接受——抱歉。有了其他答案提供的一些一般性知识,您就可以开始分清正在发生的事情了。
Y函数是“Y组合器”。现在看看
为了全面解释Y的魔法,请查看 linked article (顺便说一句,不是我写的。) |
|
|
7
16
对于那些没有深入地遇到函数式编程,不想现在就开始,但有点好奇的程序员: Y组合器是一个公式,它允许您在函数不能有名称但可以作为参数传递、用作返回值以及在其他函数中定义的情况下实现递归。 它通过将函数作为参数传递给自己来工作,因此它可以调用自己。 它是lambda微积分的一部分,它实际上是数学,但实际上是一种编程语言,对于计算机科学,特别是函数编程来说,它是非常基础的。 Y组合器的日常实用价值是有限的,因为编程语言倾向于让您命名函数。 如果你需要在警察队伍中识别它,看起来是这样的:
你通常可以发现它,因为重复
这个
|
|
|
8
12
其他答案提供了非常简洁的答案,没有一个重要的事实:您不需要以这种复杂的方式用任何实际语言实现定点组合器,这样做没有实际意义(除了“看,我知道Y组合器是什么”)。这是一个重要的理论概念,但实践价值不大。 |
|
|
9
6
下面是y-combinator和factorial函数的javascript实现(摘自Douglas Crockford的文章,网址: http://javascript.crockford.com/little.html )
|
|
|
10
6
Y组合器是磁通电容器的另一个名称。 |
|
|
11
5
我在《Clojure》和《Scheme》两本书中都为Y-Combinator写了一种“白痴指南”,以帮助自己解决这个问题。他们受到“小阴谋家”的材料影响 方案中: https://gist.github.com/z5h/238891 或Culjule: https://gist.github.com/z5h/5102747 这两个教程都是代码,中间穿插有注释,应该可以剪切到您最喜欢的编辑器中。 |
|
|
12
4
Y组合器实现匿名递归。因此,而不是
你可以做到
当然,Y组合器只在按名称调用的语言中工作。如果您想在任何按值语言的正常调用中使用它,那么您将需要相关的Z组合器(Y组合器将发散/无限循环)。 |
|
|
13
4
匿名递归
定点组合器是一个高阶函数。
自然数的阶乘可以用
使用
哪里
这样
这个正式的证据
系统地使用定点组合器等价 重写
λ演算这个 非类型化lambda微积分 形式主义包含在上下文无关的语法中
哪里
贝塔约简替换变量的所有自由出现
是
(抽象多元性)
是
(应用程序左关联性)
和
是 α当量 . 抽象和应用是lambda微积分中仅有的两个语言原语,但它们允许 编码 任意复杂的数据和操作。 教会数字是自然数字的编码,类似于皮诺公理化的自然数字。
正式的证据
使用beta缩减的重写规则:
选择符
在lambda演算中,
连接符
是不包含自由变量的抽象。最简单的是:
同构于同一函数
这种组合器是 组合计算器 就像滑雪系统。
β减少不是
强正火
;并非所有可约化表达式都在β约化下收敛到正常形式。一个简单的例子是ω的发散应用
对自己:
对最左侧的子表达式(__heads_)的简化进行了优先级排序。 应用序 在替换之前规范化参数, 正常秩序 没有。这两种策略类似于热切的评估,例如C,懒惰的评估,例如Haskell。
渴望应用阶贝塔约简下的发散
因为在 严格的 语义
但在慢正态贝塔约简下收敛
如果一个表达式有一个正态形式,正态贝塔约简会找到它。 Y
的基本属性
是由
等价性
同构于
非类型化lambda演算可以对一般/递归函数的任意构造证明进行编码。
(乘法延迟,汇合)
对于Churchian非类型lambda微积分,已经证明存在一个递归可枚举的无穷多的定点组合器,此外
正态贝塔约简使非扩展非类型化lambda演算成为一个图灵完全重写系统。 在haskell中,固定点组合器可以优雅地实现
在评估所有子表达式之前,haskell_的懒惰会正常化为有限。
|
|
|
14
3
定点组合器(或定点运算符)是计算其他函数定点的高阶函数。此操作在编程语言理论中是相关的,因为它允许以重写规则的形式实现递归,而无需语言的运行时引擎的显式支持。(SRC维基百科) |
|
|
15
3
此操作员可以简化您的生活:
然后您就可以避免额外的功能:
最后,你打电话来
|
|
|
16
2
作为组合器的新手,我发现 Mike Vanier's article (感谢尼古拉斯·曼库索)真的很有帮助。我想写一个总结,除了记录我的理解,如果能对其他人有所帮助,我会非常高兴。 从 蹩脚的 到 不那么蹩脚
以factorial为例,我们使用以下内容
在上面的伪代码中,
什么时候?
可以看出
如果我们反复通过
不那么蹩脚
factorial to的版本
固定点
事实是
这是一个非常有趣的方法,可以看到上面函数之间的关系,对我来说这是一个非常有趣的时刻。(如果没有,请阅读Mike关于固定点的帖子) 三大功能
概括地说,我们有一个
非递归
功能
总之(通过假设简化
派生
|
|
|
17
2
以下是对 original questions 编译自 the article (完全值得一读)中提到的 answer by Nicholas Mancuso 以及其他答案:
Y组合器是一个“函数”(或高阶函数“对其他函数进行操作的函数”),它接受一个参数,该参数不是递归函数,并返回一个递归函数的版本。 有点递归=),但更深入的定义是:
组合器只是一个没有自由变量的lambda表达式。
另一种考虑这一点的方法是,组合器就是这样一个lambda表达式,在这个表达式中,您可以在找到组合器的所有地方用它的定义替换它的名称,并使所有的东西都能工作(如果组合器在lambda体中包含对自身的引用,您将进入一个无限循环)。 Y组合器是一种定点组合器。
函数的固定点是由函数映射到自身的函数域的元素。
下面的例子假设 强+动态 打字:
惰性(正常顺序)Y组合器:
这意味着,对于一个给定的函数
严格(应用顺序)Y组合器:
它和懒惰的一样,只是有一个额外的
尽管Y-Combinator有一些实际的应用,但它主要是一个理论概念,对其的理解将扩展您的整体视野,并可能提高您的分析和开发技能。
AS stated by Mike Vanier : 在许多静态类型语言中定义Y组合器是可能的,但是(至少在我看到的示例中)这种定义通常需要一些不明显的类型黑客,因为Y组合器本身没有直接的静态类型。这超出了本文的范围,所以我不再赘述。 作为 mentioned by Chris Ammerman :大多数程序语言都有静态类型。 所以对这个问题的回答不是真的。 |
|
|
18
0
我认为最好的解决方法是选择一种语言,如javascript:
现在重写它,这样它就不使用函数内部的函数名,而是递归地调用它。
函数名的唯一位置
提示:不能使用函数名,但可以使用参数名。 解决问题。别查了。一旦你解决了它,你就会明白Y组合器解决了什么问题。 |
|
|
Theo Walton · 初始化静态成员使编译工作正常。。。但为什么 8 年前 |
|
|
vik santata · 如何在Haskell中编写具有初始条件的递归函数? 10 年前 |
|
|
Max Herrmann · 内联值的定义 10 年前 |
|
|
Wyllow Wulf · 要在项目Visual C中使用的函数定义++ 10 年前 |
|
|
user3437460 · 使用CSS在多个表上设置字体财产 12 年前 |