从我最近阅读的一本书中读到:
首先:
.(..)()((.))
在这一点上,最外层的lambda绑定是不可简化的,因为它没有适用的参数。剩下的就是一次进入一个层面,直到找到可以减少的东西。
下一步:
.(.)((.))
我们可以将lambda绑定应用于参数。我们一直在寻找可以申请的条款。接下来我们可以应用lambda绑定到lambda术语((.))
。
我不明白。在第一部分中,它说没有适用的参数,我可能理解,但是在下一部分我认为
z
可以绑定到((.))
,因为你可以看到,.(.)
,的主体明显有一个
z
参数可以绑定。但是这本书忽略了头部并将
n
直接绑定到((.))
。我的意思是.
没有n
参数,为什么会被绑定?
有人可以向我解释一下吗?
答案 0 :(得分:5)
使用正常的订单评估,您可以获得两次beta减少的答案
// beta reduction 1
λz.(λm.λn.m)(z)((λp.p)z) →β (λn.m) [m := z]
λz.(λm.λn.z)(z)((λp.p)z)
// beta reduction 2
λz.(λn.z)((λp.p)z) →β z [n := ((λp.p)z)]
λz.(λn.z)((λp.p)z)
// result
λz.z
第二次缩减可能看起来很棘手,因为n
绑定到((λp.p)z)
但表达式只是z
,因此n
被丢弃。
使用应用程序订单评估,需要一个额外的步骤
// beta reduction 1
λz.(λm.λn.m)(z)((λp.p)z) →β p [p := z]
λz.(λm.λn.m)(z)((λp.z)z)
// beta reduction 2
λz.(λm.λn.m)(z)(z) →β (λn.m) [m := z]
λz.(λm.λn.z)(z)(z)
// beta reduction 3
λz.(λn.z)(z) →β z [n := z]
λz.(λn.z)(z)
// result
λz.z
在这种情况下,无论我们使用正态订单评估还是应用订单评估,结果都是相同的。不同的评估策略有时会评估不同的结果。
重要提示,我们在上面执行的缩减步骤不会发生,直到 λz
被应用(取决于实现)。在您提供的示例代码中,永远不会应用λz
,因此在这种情况下,简化λz
的术语仅适用于练习。
我们所做的就是展示lambda 等价(在两种不同的评估策略下)
λz.(λm.λn.m)(z)((λp.p)z) <=> λz.z
答案 1 :(得分:4)
Lambda表示法解析有点奇怪。 IMO Haskell语法更清晰:
\z -> (\m -> \n -> m) z ((\p -> p) z)
或者,更明确的
\z -> (
(
( \m -> (\n -> m) )
z
)
( (\p -> p) z )
)
第一个减少步骤是
\z -> (
(
(\n -> z)
)
( (\p -> p) z )
)
或
\z -> (
(\n -> z)
( (\p -> p) z )
)
然后你确实可以绑定((\p -> p) z)
- 不是z
而是绑定n
! (但实际上并没有使用它。)
\z -> (
(z)
)
或只是\z -> z
。所以,我们仍然拥有z
lambda,正如本书所说的那样是不可预测的。我们什么都没有!
......我不确定这实际上是你的问题。如果它是相反的:为什么我们必须首先看看我们是否可以减少((\p -> p) z)
,那么答案是,我认为,lambda演算本身并没有定义这个(它只是定义你可以应用的转换,而不是你应该这样做的顺序。实际上我不确定这个,如果我错了,请纠正我< / SUP>)。在像Scheme这样严格的语言中,你的确会先减少((\p -> p) z)
; Haskell不会这样做,因为没有必要。无论哪种方式,它都无关紧要,因为无论如何都会丢弃结果。
( \z -> (\n -> z) ((\p -> p) z) )
≡ ( \z -> (\n -> z) z )
≡ ( \z -> (\n -> z) foo )
≡ ( \z -> z )
答案 2 :(得分:0)
关键是 n 从未在抽象中使用。 <{1}}仍然绑定到n
,但会立即丢弃。
((λp.p)z)