OpenDSA 完整目录

Chapter 29 Lambda Calculus

| 关于   «  6. Beta-归约   ::   目录   ::   8. 丘奇数与丘奇布尔值  »

7. 归约策略

7.1. 应用序(Applicative Order)

表达式 \((\lambda x.m \; (\lambda x.(x \; x) \; \lambda x.(x \; x)))\) 中有多少个 \(\beta\) 可归约式?你应该能找到两个。根据你先归约哪一个,你最终得到的"答案"可能是 \(m\),也可能是与你开始时间完全相同的那个表达式,也就是说,\(\beta\)-归约意义上的无限循环。

我们已经看到,对 \(\lambda\) 演算中表达式的求值本质上是 \(\beta\)-归约,它可以简单地用替换来定义: \((\lambda p.b \; a) \equiv subst(a,p,b)\)

但还有一个额外的因素需要考虑:前面那个 \(\beta\) 可归约式中的 \(a\) 和 \(b\) 本身可能包含 \(\beta\) 可归约式。我们需要递归地归约它们,这就提出了以下问题:

  1. 我们应该先归约哪个可归约式,顶层的可归约式,还是嵌套在内部的可归约式?

  2. 先归约哪一个有关系吗?这两种策略的后果是什么?

  3. 不同的归约策略会得到不同的结果吗?

部分回答上面第二个和第三个问题的关键是 丘奇-罗瑟定理(Church-Rosser Theorem) ,我们只陈述而不证明。根据丘奇-罗瑟定理, 如果两种不同的归约策略都得到了某个答案,那么它们将得到相同的答案。

因此,第二个和第三个问题的答案是否定的,但要加上这样的告诫:任何能得到答案的归约策略都会给出相同的答案。这里的关键是这个策略到底会不会得到答案,而丘奇-罗瑟定理既不保证停机,也不保证在答案存在时一定能找到答案。当某个策略得到的答案不能再进一步归约时,我们就说这个表达式处于 beta 范式中 (或 \(\beta\)-范式)。

JavaScript 在其替换计算模型中使用策略称为 应用序归约(applicative order reduction) 。采用这种策略,要求值形如 f(arg1, arg2, arg3, ...) 的表达式,我们:

  1. 从左到右对每个子表达式求值(如果 f 需要求值的话,也包括它)。(怎样才会需要求值呢?)

  2. 把最左边的结果——它应该是一个函数——应用于其余已经求值的子表达式。

应用序策略的特点是从左到右进行,先求值最内层的子表达式。也就是说,只有当每个子表达式都被归约、并且除了最顶层的应用之外不再存在任何可归约式时,我们才执行一次应用。考虑:

\((\lambda x.((x \; y) \; (y \; x)) \; (\lambda w.(w \; w) \; z))\)

应用序求值会先归约 \((\lambda w.(w \; w) \; z)\),得到 \((z \; z)\)。然后这个结果会被替换到 \(((x \; y) \; (y \; x))\) 中的 \(x\),得到 \((((z \; z) \; y) \; (y \; (z \; z)))\) 作为最终答案。

尽管应用序归约在上面的问题中经过两步就找到了答案,但当它用于本节考虑的第一个例子时,即

\((\lambda x.m \; (\lambda x.(x \; x) \; \lambda x.(x \; x)))\)

我们会陷入前面提到的无限循环。

7.2. 标准序(Normal Order)

标准序归约(normal order reduction) 先归约最左边的 \(\beta\) 可归约式,然后再归约它内部的子表达式以及它后面的子表达式。应用序是先求值子表达式、然后再应用函数,而标准序求值则是先应用函数、然后再求值子表达式。换句话说,标准序归约总是寻找最左边最外层的归约,而应用序总是寻找最左边最内层的归约。

因为标准序归约推迟了对函数实参的求值,所以当用于曾经让应用序无限循环的那个例子 \((\lambda\)x.m (\(\lambda x.(x \; x) \; \lambda x.(x \; x)))\) 时,它能正确地得到 \(m\)。

现在,把它用于 \((\lambda x.((x \; y) \; (y \; x)) \; (\lambda w.(w \; w) \; z))\) 时,标准序会把 \((\lambda w.(w \; w) \; z)\) 替换为 \(((x \; y) \; (y \; x))\) 中的两次 \(x\) 出现。然后它在得到最终答案 \((((z \; z) \; y) \; (y \; (z \; z)))\) 之前,必须 两次 对 \((\lambda w.(w \; w) \; z)\) 求值。

如果你仍然不能确定应用序与标准序之间的确切区别,可以使用下面的可视化工具,在各种随机的 \(\lambda\) 表达式上观察它们各自经历的步骤。一旦你有信心总是能预测可视化的下一步,就可以去做下面给出的练习了。

7.3. Beta 归约顺序(1)

下面的问题关注 \(\lambda\) 表达式在使用我们讨论过的两种求值策略进行求值时,其第一步(即 \(\beta\)-归约)。要获得这个随机练习的学分,你必须连续三次答对。

7.4. Beta 归约顺序(2)

在下面的问题中,你必须用我们讨论过的两种求值策略研究一个 \(\lambda\) 表达式的完整求值过程。要获得这个随机练习的学分,你必须连续三次答对。

7.5. 应用序熟练度练习

在下面的问题中,你必须对一个随机选择的 \(\lambda\) 表达式进行完整的求值,也就是说,执行尽可能多的 \(\beta\)-归约,直到达到 \(\beta\) 范式。对于这个问题,你必须使用 应用序 归约策略。要获得这道题的学分,你只需要正确解决一个问题实例。然而,每个问题实例包含多个步骤,你必须全部正确完成(本例中,每一步都是一次 \(\beta\)-归约)。请仔细阅读并遵循操作说明。注意,存在正确答案(称为 参考答案 )。不过,如果你查看了它,你将无法获得当前问题实例的学分。要获得另一次机会,请点击 重置 按钮开始一个新的问题实例。

7.6. 标准序熟练度练习

在下面的问题中,你必须对一个随机选择的 \(\lambda\) 表达式进行完整的求值,也就是说,执行尽可能多的 \(\beta\)-归约,直到达到 \(\beta\) 范式。对于这个问题,你必须使用 标准序 归约策略。要获得这道题的学分,你只需要正确解决一个问题实例。然而,每个问题实例包含多个步骤,你必须全部正确完成(本例中,每一步都是一次 \(\beta\)-归约)。请仔细阅读并遵循操作说明。注意,存在正确答案(称为 参考答案 )。不过,如果你查看了它,你将无法获得当前问题实例的学分。要获得另一次机会,请点击 重置 按钮开始一个新的问题实例。

   «  6. Beta-归约   ::   目录   ::   8. 丘奇数与丘奇布尔值  »

关闭窗口