所述λ演算,或演算,是根据匿名功能的逻辑系统。例如,这是一个λ表达式:
λf.(λx.xx)(λx.f(xx))
但是,出于此挑战的目的,我们将简化表示法:
- 更改
λ
为\
(以便于键入):\f.(\x.xx)(\x.f(xx))
- 该
.
拉姆达头是不必要的,所以我们可以删除它:\f(\xxx)(\xf(xx))
- 在应用程序中使用Unlambda样式的前缀表示法,
`
而不是将两个函数一起编写(有关如何执行此操作的完整说明,请参见在Lambda微积分表示法之间转换):\f`\x`xx\x`f`xx
- 这是最复杂的替换。根据变量相对于其所属的lambda标头的嵌套深度(即,使用基于0的De Bruijn索引),用括号中的数字替换每个变量。例如,在
\xx
(身份函数)中,x
主体中的in将替换为[0]
,因为它属于在将表达式从变量遍历到末尾时遇到的第一个(从0开始)头。\x\y``\x`xxxy
将被转换为\x\y``\x`[0][0][1][0]
。现在,我们可以将变量放在标头中,离开\\``\`[0][0][1][0]
。
组合逻辑基本上是由λ微积分构成的Turing Tarpit(嗯,实际上,它是第一位的,但是在这里无关紧要。)
“组合逻辑可以看作是lambda演算的一种变体,其中lambda表达式(代表功能抽象)被有限的组合器集合所取代,这些组合器不存在绑定变量。1个
组合逻辑最常见的类型是SK组合器演算,它使用以下原语:
K = λx.λy.x
S = λx.λy.λz.xz(yz)
有时I = λx.x
会添加一个组合器,但它是多余的,因为SKK
(或实际上SKx
对任何而言x
)都等同于I
。
您只需要K,S和应用程序即可编码λ微积分中的任何表达式。例如,这是从函数λf.(λx.xx)(λx.f(xx))
到组合逻辑的转换:
λf.(λx.xx)(λx.f(xx)) = S(K(λx.xx))(λf.λx.f(xx))
λx.f(xx) = S(Kf)(S(SKK)(SKK))
λf.λx.f(xx) = λf.S(Kf)(S(SKK)(SKK))
λf.S(Sf)(S(SKK)(SKK)) = S(λf.S(Sf))(K(S(SKK)(SKK)))
λf.S(Sf) = S(KS)S
λf.λx.f(xx) = S(S(KS)S)(K(S(SKK)(SKK)))
λx.xx = S(SKK)(SKK)
λf.(λx.xx)(λx.f(xx)) = S(K(S(SKK)(SKK)))(S(S(KS)S)(K(S(SKK)(SKK))))
由于我们使用的是前缀表示法,因此为```S`K``S``SKK``SKK``S``S`KSS`K``SKK`
。
1资料来源:维基百科
挑战
到目前为止,您可能已经猜到了什么:编写一个程序,该程序将有效的λ表达式(以上述符号表示)作为输入和输出(或返回)相同的函数,并用SK组合器演算重写。注意,有无数种方法可以重写它。您只需要输出无限方式之一。
这是代码高尔夫球,因此最短的有效提交(以字节为单位)获胜。
测试用例
每个测试用例都显示一个可能的输出。最上面的表达式是等效的λ微积分表达式。
λx.x:
\[0] -> ``SKK
λx.xx:
\`[0][0] -> ```SKK``SKK
λx.λy.y:
\\[0] -> `SK
λx.λy.x:
\\[1] -> K
λx.λy.λz.xz(yz):
\\\``[2][0]`[1][0] -> S
λw.w(λx.λy.λz.xz(yz))(λx.λy.x):
\``[0]\\[1]\\\``[2][0]`[1][0] -> ``S``SI`KS`KK
λx.f(xx) = S(Kf)(SKK)
?不应该这样λx.f(xx) = S(Kf)(SII) = S(Kf)(S(SKK)(SKK))
吗?转换时λx.f(xx)
,我得到S {λx.f} {λx.xx}
归S (Kf) {λx.xx}
约为,方括号中的表达式就是ω=λx.xx
,我们知道它表示为SII = S(SKK)(SKK)
,对吗?
SII
,不是SKK
。那是个错误。