Y组合是一个计算机科学的概念从"职能"方面的事情。大多数程序员不知道很多有关的组合器,如果他们甚至已经听取了关于他们。

  • 什么是Y-组合?
  • 如何组合子的工作?
  • 它们是什么好处?
  • 他们是有用的,在程序性的语言?
有帮助吗?

解决方案

如果你准备好了只要阅读, 迈克*凡尼尔有一个 伟大的 解释.长话短说,它可以让你实现递归的语言,这并不一定支持它本身。

其他提示

Y组合是一种"功能性"(功能操作的其他职能),使递归的时候你可以不参阅的职能从内的本身。在计算机科学的理论, 概括递归,抽象其实施,并由此脱离实际工作的职能中的问题。的利益,不需要编译时间名字递归功能是一种奖励。=)

这是可适用的语言支持 lambda功能.的 表达基于性lambda通常意味着它们不能引用自己的姓名。和周围的工作,这通过的声明的变量,为参照,然后分配lambda,以完成自参循环,为脆弱。Lambda变量可以复制的,与原始变量重新分配,这会破坏自参考。

Y组合子是繁琐的实施,并经常使用, 静态型 语言(它 程序性语言 往往正),因为通常的打字的限制,需要参数的数量的功能,在问题是在编译时间。这意味着,一个y组合必须是书面的任何论点数,其中一个需要使用。

下面是一个如何使用和工作的Y-组合,在C#。

使用Y组合涉及一个"异常"的方式构建一个递归功能。首先,你必须写你的功能作一段代码,电话预先存在的功能,而不是本身:

// Factorial, if func does the same thing as this bit of code...
x == 0 ? 1: x * func(x - 1);

然后你把这一成功,需要一个功能调和返回的一个函数,这样做。这就是所谓的功能,因为它需要一个功能,并执行一个运作,结果在另一个功能。

// A function that creates a factorial, but only if you pass in
// a function that does what the inner function is doing.
Func<Func<Double, Double>, Func<Double, Double>> fact =
  (recurs) =>
    (x) =>
      x == 0 ? 1 : x * recurs(x - 1);

现在你有一个函数的一个函数,以及返回的另一个功能,这种看起来像一个因子,而是自称,它要求参数通过进入外层的功能。你怎么让这个因子?通过内部职能本身。Y组合并,由一个功能与永久性的名字,这可以介绍递归。

// One-argument Y-Combinator.
public static Func<T, TResult> Y<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> F)
{
  return
    t =>  // A function that...
      F(  // Calls the factorial creator, passing in...
        Y(F)  // The result of this same Y-combinator function call...
              // (Here is where the recursion is introduced.)
        )
      (t); // And passes the argument into the work function.
}

而不是因子叫本身,会发生什么情况是,因话的因子生成器(返回通过递归呼吁Y组合).并且取决于当前的t值的功能返回从发电机将呼叫的再次发生器,t-1,或者只是返回1,终止递归。

它是复杂的和神秘,但它的所有动摇在运行时,关键工作是"推迟执行",并破坏的递归,跨越两个功能。内F 通过作为一个参数, 称在下一次迭代, 只有如果有必要.

我已经解除这种从 http://www.mail-archive.com/boston-pm@mail.pm.org/msg02716.html 这是一个解释我写了几年前。

我会用JavaScript在这个例子中,但许多其他语言的工作。

我们的目标是能够编写递归功能的1 变量使用的唯一职能的1个变量并没有 工作分配,确定名字的东西,等等。(为什么这是我们的 目标是另外一个问题,我们只是把此作为 挑战,我们正在给定。) 似乎是不可能的,对吧?作为 一个例子,让我们实现的因素。

好步骤1是说,我们可以很容易地做到这一点,如果我们 欺骗一点。使用功能的变量和2 分配我们至少可以避免使用 分配给设立的递归。

// Here's the function that we want to recurse.
X = function (recurse, n) {
  if (0 == n)
    return 1;
  else
    return n * recurse(recurse, n - 1);
};

// This will get X to recurse.
Y = function (builder, n) {
  return builder(builder, n);
};

// Here it is in action.
Y(
  X,
  5
);

现在让我们来看看如果我们可以欺骗下。好的首先我们使用 分配,但我们不需要。我们只能写和X Y内联。

// No assignment this time.
function (builder, n) {
  return builder(builder, n);
}(
  function (recurse, n) {
    if (0 == n)
      return 1;
    else
      return n * recurse(recurse, n - 1);
  },
  5
);

但是,我们正在使用功能的2个变量,以获得一个函数的1 变量。我们能解决吗?好了聪明的家伙的名字 Haskell咖喱有一个绝招,如果你有好高了 功能,那么你只需要职能的1个变量。的 证明是,你可以从职能的2个(或多个的 一般情况)的变量为1变量有一个纯粹的 机械的文本转变这样的:

// Original
F = function (i, j) {
  ...
};
F(i,j);

// Transformed
F = function (i) { return function (j) {
  ...
}};
F(i)(j);

在哪里...仍然完全相同。(这一招呼 "柯里化"之后,它的发明者。语言Haskell也是 命名为Haskell咖喱。文件下无益的琐事。) 现在只适用于这种转变无处不在,我们得到 我们的最终版本。

// The dreaded Y-combinator in action!
function (builder) { return function (n) {
  return builder(builder)(n);
}}(
  function (recurse) { return function (n) {
    if (0 == n)
      return 1;
    else
      return n * recurse(recurse)(n - 1);
  }})(
  5
);

随意尝试它。警报()就返回,把它绑在一个按钮什么的。这代码计算阶乘,递归的,而无需使用 分配、声明、或职能2的变量。(但是 试图追踪它是如何工作的可能让你晕头转.和移交,而不导,只要稍微重新格式化 将会导致的代码一定要挡板和混淆。)

你可以替代的4行,递归的定义因素与 任何其他递归功能。

我不知道如果有任何使用在试图建立这个从地上爬起来。让我们来看看。这是一个基本的,递归因素的功能:

function factorial(n) {
    return n == 0 ? 1 : n * factorial(n - 1);
}

让我们重构和创建一个新的功能叫 fact 返回匿名因子计算功能,而不是执行的计算:

function fact() {
    return function(n) {
        return n == 0 ? 1 : n * fact()(n - 1);
    };
}

var factorial = fact();

那是有点怪异,但没有什么是错误的。我们只是产生一个新的因素的功能,在每个步骤。

递归在这一阶段仍然是相当明确的。的 fact 功能需要了解其自己的名字。让我们参数化的递归的呼吁:

function fact(recurse) {
    return function(n) {
        return n == 0 ? 1 : n * recurse(n - 1);
    };
}

function recurser(x) {
    return fact(recurser)(x);
}

var factorial = fact(recurser);

这是伟大的,但 recurser 仍然需要知道自己的名称。让我们参数化,也:

function recurser(f) {
    return fact(function(x) {
        return f(f)(x);
    });
}

var factorial = recurser(recurser);

现在,而不是呼叫 recurser(recurser) 直接,让我们创建一个包装的功能返回其结果是:

function Y() {
    return (function(f) {
        return f(f);
    })(recurser);
}

var factorial = Y();

我们现在可以摆脱的 recurser 名字完全;它只是一个参数之内的功能,这可以被替换的功能,本身:

function Y() {
    return (function(f) {
        return f(f);
    })(function(f) {
        return fact(function(x) {
            return f(f)(x);
        });
    });
}

var factorial = Y();

唯一的外部名称仍然是引用 fact, 但应该清楚现在,这是很容易的参数化,也创造完成后,通用的解决方案:

function Y(le) {
    return (function(f) {
        return f(f);
    })(function(f) {
        return le(function(x) {
            return f(f)(x);
        });
    });
}

var factorial = Y(function(recurse) {
    return function(n) {
        return n == 0 ? 1 : n * recurse(n - 1);
    };
});

大多数答复上面的描述是什么Y组合 但不是它是什么 对于.

固定点的组合器 是用来表明, 氧微积分图灵完成.这是一个非常重要的结果,在计算理论和提供了理论基础 编程功能.

研究的固定点的组合子也帮助我真的很理解功能的程序。我从来没有发现任何使用他们在实际编程。

y在组合 JavaScript:

var Y = function(f) {
  return (function(g) {
    return g(g);
  })(function(h) {
    return function() {
      return f(h(h)).apply(null, arguments);
    };
  });
};

var factorial = Y(function(recurse) {
  return function(x) {
    return x == 0 ? 1 : x * recurse(x-1);
  };
});

factorial(5)  // -> 120

编辑:我学习了很多看码,但是这一次是有点难以下咽,没有一些背景-对不起有一些一般性的知识提出的其他答复,您可以开始挑选除了发生了什么。

Y功能的"y-组合".现在看看 var factorial 行Y是用。注意到你传递一个函数,有一个参数(在这个例子中, recurse),还用于后来在内的功能。参名称基本上变成了名的内的功能允许其执行递归呼吁(因为它使用 recurse() 在它的定义。) Y组合进行的魔法的关联,否则匿名内部的功能与参名称的功能传递给Y。

为充分解释如何Y没有魔法,检查了 链接的文章 (不由我顺便说一句.)

为程序员,他们还没有遇到编程功能在深度,以及不管现在开始,但被客气一点好奇:

该Y组合是一个公式,它可以让你实现递归在一个情况下,职能不能有名字,但是可以通过周围的参数,用作回值,并定义内的其他功能。

它的工作通过的功能本身作为一个参数,所以它可以叫本身。

它的一部分氧微积分,这是真的,数学,但实际上是一种编程语言,并且是非常基本的计算机科学和尤其是功能性的程序。

一天一天的实用价值的Y组合是有限的,因为编程语言倾向于让你名字的功能。

在情况需要确定它在警方的阵容,它看起来像这样:

Y=λf.(λx.f(x))(λx.f(x))

你通常可以发现它,因为重复 (λx.f (x x)).

λ 符号是希腊字母lambda,这给lambda演算将其名称,并且有很多 (λx.t) 风格的条款,因为这是氧微积分的外观。

其他的答案提供相当简明扼要的答案,而不的一个重要的事实:你不需要实施定点组合中的任何实际的语言这种令人费解的方式,这样做没有任何实际的目的(除了"你看,我知道Y组合是")。这是重要的理论概念,但很少实际价值。

这里是一个JavaScript执行Y组合和因素的功能(从道格拉斯Crockford的文可在: http://javascript.crockford.com/little.html).

function Y(le) {
    return (function (f) {
        return f(f);
    }(function (f) {
        return le(function (x) {
            return f(f)(x);
        });
    }));
}

var factorial = Y(function (fac) {
    return function (n) {
        return n <= 2 ? n : n * fac(n - 1);
    };
});

var number120 = factorial(5);

Y组合是另一个名称为通量电容器。

我已经写入了一种"白痴的指南"Y-组合中既有质量的技术资源和方案,以便帮助自己来掌握它。他们有影响的材料"的小阴谋家"

在方案:https://gist.github.com/z5h/238891

或题:https://gist.github.com/z5h/5102747

这两个教程码穿插的意见,并应削减和pastable到你喜欢编辑器。

匿名递归

一个定点的组合是一个高级功能 fix 通过定义满足的等同性

forall f.  fix f  =  f (fix f)

fix f 代表一个解决方案 x 到定点公式

               x  =  f x

因子的一个自然人数可以证明

fact 0 = 1
fact n = n * fact (n - 1)

使用 fix, 任意建设性的证据一般/μ递归功能,可得出不nonymous自referentiality.

fact n = (fix fact') n

哪里

fact' rec n = if n == 0
                then 1
                else n * rec (n - 1)

这样,

   fact 3
=  (fix fact') 3
=  fact' (fix fact') 3
=  if 3 == 0 then 1 else 3 * (fix fact') (3 - 1)
=  3 * (fix fact') 2
=  3 * fact' (fix fact') 2
=  3 * if 2 == 0 then 1 else 2 * (fix fact') (2 - 1)
=  3 * 2 * (fix fact') 1
=  3 * 2 * fact' (fix fact') 1
=  3 * 2 * if 1 == 0 then 1 else 1 * (fix fact') (1 - 1)
=  3 * 2 * 1 * (fix fact') 0
=  3 * 2 * 1 * fact' (fix fact') 0
=  3 * 2 * 1 * if 0 == 0 then 1 else 0 * (fix fact') (0 - 1)
=  3 * 2 * 1 * 1
=  6

这一正式证据,证明

fact 3  =  6

有条不紊地使用定点组合等同于 重写

fix fact'  ->  fact' (fix fact')

氧微积分

无类型的氧微积分 形式主义,包括在一个方面。

E ::= v        Variable
   |  λ v. E   Abstraction
   |  E E      Application

哪里 v 范围上的变量,同 betaeta减少 规则

(λ x. B) E  ->  B[x := E]                                 Beta
  λ x. E x  ->  E          if x doesn’t occur free in E   Eta

测试替代品减少所有自由发生的变量 x 在抽象("功能")的身体 B 由的表达("argument") E.Eta减少消除了多余的抽象概念。它有时是省略了形式主义。一个 束缚 表达,这没有减少规则的适用,是在 正常的规范的形式.

λ x y. E

是的缩写

λ x. λ y. E

(抽象multiarity),

E F G

是的缩写

(E F) G

(应用左关联性),

λ x. x

λ y. y

alpha-等同.

抽象和应用的是两只有"用语的原语"lambda微积分,但它们允许 编码 随意复杂的数据和操作。

教会数字编码的自然数字相似皮亚诺-不言自明的土黄。

   0  =  λ f x. x                 No application
   1  =  λ f x. f x               One application
   2  =  λ f x. f (f x)           Twofold
   3  =  λ f x. f (f (f x))       Threefold
    . . .

SUCC  =  λ n f x. f (n f x)       Successor
 ADD  =  λ n m f x. n f (m f x)   Addition
MULT  =  λ n m f x. n (m f) x     Multiplication
    . . .

一个正式的证明

1 + 2  =  3

使用重写规则的减少:

   ADD                      1            2
=  (λ n m f x. n f (m f x)) (λ g y. g y) (λ h z. h (h z))
=  (λ m f x. (λ g y. g y) f (m f x)) (λ h z. h (h z))
=  (λ m f x. (λ y. f y) (m f x)) (λ h z. h (h z))
=  (λ m f x. f (m f x)) (λ h z. h (h z))
=  λ f x. f ((λ h z. h (h z)) f x)
=  λ f x. f ((λ z. f (f z)) x)
=  λ f x. f (f (f x))                                       Normal form
=  3

组合子

在氧微积分 组合子 是抽象概念,包含下没有免费的变量。最简单: I, 身份组合

λ x. x

同构的身份的功能

id x = x

这种组合子是原始经营者 组合的结石 喜欢滑雪系统。

S  =  λ x y z. x z (y z)
K  =  λ x y. x
I  =  λ x. x

Beta减少不是 强烈正常化;不是所有的还原性的表达,"redexes",收敛到正常的形式下测试减少。一个简单的例子是不同的应用程序的欧米茄 ω 组合

λ x. x x

到本身:

   (λ x. x x) (λ y. y y)
=  (λ y. y y) (λ y. y y)
. . .
=  _|_                     Bottom

减少的最左子表达式("头")是优先考虑。 应用了 恢复正常的参数之前替换, 正常秩序 不。两个战略都类似于急切的评估,例如C,和懒惰的评价,例如Haskell.

   K          (I a)        (ω ω)
=  (λ k l. k) ((λ i. i) a) ((λ x. x x) (λ y. y y))

发散下的渴望应用阶测试减少

=  (λ k l. k) a ((λ x. x x) (λ y. y y))
=  (λ l. a) ((λ x. x x) (λ y. y y))
=  (λ l. a) ((λ y. y y) (λ y. y y))
. . .
=  _|_

由于在 严格 语义

forall f.  f _|_  =  _|_

但是收敛下懒正常-以减少测试

=  (λ l. ((λ i. i) a)) ((λ x. x x) (λ y. y y))
=  (λ l. a) ((λ x. x x) (λ y. y y))
=  a

如果一个表达有一个正常的形式,正常-以测试减少会找到它。

Y

重要的财产 Y 定点组合

λ f. (λ x. f (x x)) (λ x. f (x x))

是给予

   Y g
=  (λ f. (λ x. f (x x)) (λ x. f (x x))) g
=  (λ x. g (x x)) (λ x. g (x x))           =  Y g
=  g ((λ x. g (x x)) (λ x. g (x x)))       =  g (Y g)
=  g (g ((λ x. g (x x)) (λ x. g (x x))))   =  g (g (Y g))
. . .                                      . . .

等价

Y g  =  g (Y g)

是同构

fix f  =  f (fix f)

的类型氧微积分可以进行编码任意建设性的证据一般/μ递归功能。

 FACT  =  λ n. Y FACT' n
FACT'  =  λ rec n. if n == 0 then 1 else n * rec (n - 1)

   FACT 3
=  (λ n. Y FACT' n) 3
=  Y FACT' 3
=  FACT' (Y FACT') 3
=  if 3 == 0 then 1 else 3 * (Y FACT') (3 - 1)
=  3 * (Y FACT') (3 - 1)
=  3 * FACT' (Y FACT') 2
=  3 * if 2 == 0 then 1 else 2 * (Y FACT') (2 - 1)
=  3 * 2 * (Y FACT') 1
=  3 * 2 * FACT' (Y FACT') 1
=  3 * 2 * if 1 == 0 then 1 else 1 * (Y FACT') (1 - 1)
=  3 * 2 * 1 * (Y FACT') 0
=  3 * 2 * 1 * FACT' (Y FACT') 0
=  3 * 2 * 1 * if 0 == 0 then 1 else 0 * (Y FACT') (0 - 1)
=  3 * 2 * 1 * 1
=  6

(乘延迟交汇处)

为Churchian类型氧微积分,那里已经显示出存在一种递归的。无限的固定点的组合器除了 Y.

 X  =  λ f. (λ x. x x) (λ x. f (x x))
Y'  =  (λ x y. x y x) (λ y x. y (x y x))
 Z  =  λ f. (λ x. f (λ v. x x v)) (λ x. f (λ v. x x v))
 Θ  =  (λ x y. y (x x y)) (λ x y. y (x x y))
  . . .

正了测试减少使未扩展类型氧微积分图灵-完全重写系统。

在Haskell,定点组合可以是优雅的实施

fix :: forall t. (t -> t) -> t
fix f = f (fix f)

Haskell的懒惰恢复正常的一个菲堤前所有子表达式已经进行评价。

primes :: Integral t => [t]
primes = sieve [2 ..]
   where
      sieve = fix (\ rec (p : ns) ->
                     p : rec [n | n <- ns
                                , n `rem` p /= 0])

Y组合的实现匿名递归。因此,不是的

function fib( n ){ if( n<=1 ) return n; else return fib(n-1)+fib(n-2) }

你可以做的

function ( fib, n ){ if( n<=1 ) return n; else return fib(n-1)+fib(n-2) }

当然,y-只有组合的工作在按名的语言。如果你想使用此在任何正常的电话通值的语言,然后你会需要的相关z组合(y组合将出现分歧/无限循环)。

作为一个新手来组合子,我发现 迈克*凡尼尔的文章 (感谢尼古拉斯Mancuso)是真的很有帮助。我想写一个概要,除了记录我的理解是,如果这可能有助于其他一些人,我将非常高兴。

蹩脚少蹩脚

使用因子为例,我们用以下的 almost-factorial 功能的计算因子的数量 x:

def almost-factorial f x = if iszero x
                           then 1
                           else * x (f (- x 1))

在上述伪码, almost-factorial 需要在功能 f 和数量 x (almost-factorial 是咖喱,所以它可以看作在功能 f 和返回的一个1-数功能)。

almost-factorial 计算因子为 x, 它代表计算的因为 x - 1 功能 f 和积累,结果与 x (在这种情况下,它繁殖的结果(x-1)x)。

它可以被看作是 almost-factorial 需要在一个 蹩脚 版本因素的功能(这只能计算,直到号码 x - 1)和返回 不太蹩脚 版本的因子(其中计算,直到号码 x).作为在这种形式:

almost-factorial crappy-f = less-crappy-f

如果我们反复通过 不太蹩脚 版本的因素, almost-factorial, 我们最终将获得我们所希望的因素的功能 f.在那里它可以被认为是为:

almost-factorial f = f

修正点

事实上, almost-factorial f = f 装置 f 是的 修正点 的功能 almost-factorial.

这是一个非常有趣的方式看的关系的职能上,这是一个哈时刻对我来说。(请阅读迈克的后在解决-一点如果你还没有)

三个功能

一概而论,我们有一个 非recursive 功能 fn (像我们几乎因素),我们有它 修正点 功能 fr (喜欢我们的f),然后是什么 Y 不是当你得到 Y fn, Y 返回的修正点的功能 fn.

因此,在总结(简化的假设 fr 只需要一个参数; x 堕落到 x - 1, x - 2...在递归):

  • 我们定义的 核心计算 作为 fn: def fn fr x = ...accumulate x with result from (fr (- x 1)), 这是的 几乎的-有用的 功能--尽管我们不能使用 fn 直接上 x, 它将是有用的很快。这不递 fn 用一个功能 fr 计算结果
  • fn fr = fr, fr 是的修正点的 fn, fr 是的 有用的 主要功能,我们可以使用 frx 让我们结果
  • Y fn = fr, Y 返回的修正点的功能, Y 变成我们 几乎的-有用的 功能 fn有用的 fr

得出 Y (不包括)

我会跳过导的 Y 去了解 Y.迈克Vainer后有很多的细节。

形式 Y

Y 被定义为(在 氧微积分 格式):

Y f = λs.(f (s s)) λs.(f (s s))

如果我们替代变量 s 在左边的功能,我们得到

Y f = λs.(f (s s)) λs.(f (s s))
=> f (λs.(f (s s)) λs.(f (s s)))
=> f (Y f)

所以事实上的结果 (Y f) 是的修正点的 f.

为什么 (Y f) 工作?

根据签名的 f, (Y f) 可以是一个函数的任何数,以简化,让我们假设 (Y f) 只需要一个参数,就像我们的因素的功能。

def fn fr x = accumulate x (fr (- x 1))

由于 fn fr = fr, 我们继续

=> accumulate x (fn fr (- x 1))
=> accumulate x (accumulate (- x 1) (fr (- x 2)))
=> accumulate x (accumulate (- x 1) (accumulate (- x 2) ... (fn fr 1)))

递归算终止时,最里面 (fn fr 1) 是的基本情况和 fn 不使用 fr 在计算。

Y 再次:

fr = Y fn = λs.(fn (s s)) λs.(fn (s s))
=> fn (λs.(fn (s s)) λs.(fn (s s)))

所以

fr x = Y fn x = fn (λs.(fn (s s)) λs.(fn (s s))) x

我说,神奇的部分安装是:

  • fnfr interdepend上每一个其它: fr '包装' fn 在内部,每个时间 fr 用于计算 x, 这会产生'('电梯'?) 一个 fn 和代表的计算, fn (通过在本身 frx);另一方面, fn 取决于 fr 和使用 fr 计算结果较小的问题 x-1.
  • 在时间 fr 用来定义 fn (当 fn 使用 fr 在其运作),该实 fr 尚未定义。
  • 它的 fn 它定义了真正的商业逻辑。基于上 fn, Y 创建 fr -一个辅助功能在一个具体的形式,以便于计算 fn 在一个 递归 方式。

它帮助我了解 Y 这样的时刻,希望这有所帮助。

顺便说一句,我还找到了这本书 介绍编程功能,通过氧微积分 很好,我只是部分通过它与事实上,我不能让我的头周围 Y 在书中,导致我到这一员额。

这里有答案 原来的问题, 汇编从 该文章 (这是完全值得一读)中提到的 答案由尼古拉斯Mancuso, 以及其他的答案:

什么是Y-组合?

一个Y组合是一种"功能性"(或者更高的阶函数的一个函数的运作上的其他职能),需要一个单一的论点,这是一个函数,并不递归,并返回一个版本的功能是递归的。


有些递归=),但更深入的定义:

一个组合—只是一个lambda的表达有没有免费的变量。
免费的变是一个变量,不一定变量。
定变量的变量载体内部的一氧表达了变量名称作为其论据。

另一种方式来想想这个是组合就是这样一个lambda表达,你是能够替换该名称一个组合与其定义无处不在,它是找到和拥有的一切仍然可以工作(你会进入一个无限的循环,如果组合将包含参考本身内部的氧体)。

Y组合是一个固定点的组合.

固定点的一个函数是一个元素的功能领域就是映射到本身的功能。
这就是说, c 是一个固定点的功能 f(x) 如果 f(c) = c
这意味着 f(f(...f(c)...)) = fn(c) = c

如何组合子的工作?

下面的例子承担 强大的动态 键入:

懒惰的(正常秩序)Y组合的:
这个定义适用于语言与懒(:推迟了,电话分需要)评价评估的战略,延缓评估的一种表达,直到它的价值是必要的。

Y = λf.(λx.f(x x)) (λx.f(x x)) = λf.(λx.(x x)) (λx.f(x x))

这意味着,对于一个特定功能 f (这是一个非递归功能),相应的递归功能,可以获得第一个通过计算 λx.f(x x), ,然后应用该lambda表达本身。

严格的(应用阶)Y组合的:
这个定义适用于语言的严格(也:渴望,贪婪的)评价,评价战略,在其中一个表达式进行评估时,尽快开一个变量。

Y = λf.(λx.f(λy.((x x) y))) (λx.f(λy.((x x) y))) = λf.(λx.(x x)) (λx.f(λy.((x x) y)))

它是一样的懒之一,在它的性质,它只是有一个额外的 λ 包装推迟lambda的体评价。我们已经问了 另一个问题, 有点有关这个问题。

它们是什么好处?

偷来的 借用 答案由克里斯*Ammerman:Y组合的概括递归,抽象其实施,并由此脱离实际工作的职能中的问题。

即使Y组合中有一些实际应用,它主要是一个理论概念,了解其将扩大你的整体愿景,并将有可能提高你的分析和开发技能。

他们是有用的,在程序性的语言?

作为 说迈克*凡尼尔: 它是可能的定义Y组合,在许多类型的静态语言,但是(至少在例子我已经看到的)这样的定义通常需要一些非显而易见的类型车呀,因为Y组合本身没有一个简单的静态型的。这超出了本文的范围,所以我不会提到这一步

和为 提到克里斯Ammerman:大多数程序性的语言有静-打字。

所以回答这一个—不是真的。

一点固定组合(或定点操作员)是一个高阶函数计算的固定点的其他职能。这种操作是相关的,在编程语言论,因为它允许执行递归的形式重写规则,而不明确的支持,从语言的运行发动机。(src维基百科)

这个运营商可以简化你的生活:

var Y = function(f) {
    return (function(g) {
        return g(g);
    })(function(h) {
        return function() {
            return f.apply(h(h), arguments);
        };
    });
};

那么你避免额外的功能:

var fac = Y(function(n) {
    return n == 0 ? 1 : n * this(n - 1);
});

最后,你呼叫 fac(5).

我认为最佳的方式回答这个是选择一种语言,例如JavaScript:

function factorial(num)
{
    // If the number is less than 0, reject it.
    if (num < 0) {
        return -1;
    }
    // If the number is 0, its factorial is 1.
    else if (num == 0) {
        return 1;
    }
    // Otherwise, call this recursive procedure again.
    else {
        return (num * factorial(num - 1));
    }
}

现在重写,使其不使用名称的功能内部的功能,但是仍然呼它。

只有名称的功能 factorial 应该看到是在电话网站。

提示:你不能使用名称的功能,但是可以使用的名称参数。

工作的问题。不看看它。一旦你了解决它,你就会明白什么问题y组合的解决。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top