231
社区成员
课程信息:https://bbs.csdn.net/topics/608593392
第二节作业提交帖:https://bbs.csdn.net/topics/608988912
Implement the substitution function N[v/x] : subst (N: lambda, x: string, v: value) : lambda
Think about how substitution works on arbitrary terms, i.e. N[M/x] where M could contain free variables.
Implement Church numberals and arithmetic functions using lambda calculus
实现归约函式(body[va/x]),函式签名为substitution(x, va, body, parameters),其中parameters为此函式参数名集合,用以避免重命名冲突
若变量名y与x相同(y==x),即是同x[va/x],故归约为va;否则同y[va/x],故归约为Var(y)。
依归约原则,依次执行m[va/x]、n[va/x]。
即(λp.(lambda))[va/x]
// 歸約替換
let rec substitution = (x, va, body, parameters) => {
let (v, fv) = va
switch body {
| Var(y) =>
if y == x {
v
} else {
body
}
| Fun(p, lambda) =>
if x == p {
body
} else if fv->List.has(p, String.equal) {
// 傳入值的自由變量名集合跟函式項的p參數名發生衝突時,則進行相關處理
let new_p = fresh_name(p, parameters)
let new_lambda = rename(lambda, p, new_p)
Fun(new_p, substitution(x, va, new_lambda, list{new_p, ...parameters}))
} else {
Fun(p, substitution(x, va, lambda, parameters))
}
| App(m, n) => {
/*
* 若歸約函式項主體的調用鏈上,存在着局部子函式項,則取該子函式項的參數名集合,
* 以避免歸約該子函式項時,受到原父歸約函式項參數名的污染
*/
let m_parameters = switch m {
| Fun(_, _) => get_parameters(m)
| _ => parameters
}
let n_parameters = switch n {
| Fun(_, _) => get_parameters(n)
| _ => parameters
}
let m' = substitution(x, va, m, m_parameters)
let n' = substitution(x, va, n, n_parameters)
App(m', n')
}
}
}
假设我们传入的lambda是close的,并假设其项式为App(...(((Fun/1->Fun/2->...->Fun/n)N/1)N/2)...)N/n),我们来用语言模拟下程式运行。
进入App闭项分支。
通过判断,存在未被归约的函式项,归约Fun/1->Fun/2
此时闭项的左侧是Fun类闭项,因此进入此分支
Fun/2是函式项,我们采取惰性归约的策略。因为,若Fun/2是omega算式,即(λx.xx)(λx.xx),直接归约会导致程式陷入无限循环
我们设此归约结果为Fun/(1'/2)。
即当(Fun/1->Fun/2->...->Fun/n)被(N/1 N/2 ... N/n)全部归约彻底时,这是必然的事情,因为我们假设的lambda是close的。
而此时,我们离底部还差m深度个距离,必须直接返回。否则,假如若Fun/1是omega算式,那么,归约Fun/(1'/2)的函式body的结果也必然是无限循环。
depth的计算比较粗略,就是离最外围的括号多少距离。
ma即为步骤三的Fun/(1'/2),即步骤四的执行结果,跳出后到达此处,位于步骤二之后。
重复步骤三、步骤四、步骤五,直至(Fun/1->Fun/2->...->Fun/n)被(N/1 N/2 ... N/n)全部归约彻底。
因为是close的,必然会调至步骤六,该处对归约出来的函式项body进一步执行归约,跳回步骤一
后续可以用邱奇数的不定点算子公式F = F(YF),进行具体阐释。
let reduce = lambda => {
let rec reduce_inner = (lambda, depth) => {
switch lambda {
| Var(_) => lambda
| Fun(x, body) => Fun(x, reduce_inner(body, 0)) // 步骤六
| App(m, n) => // 步骤一
// 閉項調用鏈處理
switch m {
| Fun(x, body) => { // 步骤三
// 對受控函式項進行歸約,Call by value
// 此处必须判断函式主体是否含变量名x,否则w演算時會無限循環
// 为何会无限循环,太烧脑,没去想了
let r = if has_free_variable(body, x) {
let parameters = get_parameters(m)
let fv = get_free_variables(n)
let v = switch n {
// w演算時,函式項需延遲處理,不然會無限循環
| Fun(_, _) => n
| _ => reduce_inner(n, depth)
}
substitution(x, (v, fv), body, parameters)
} else {
body
}
// 若此函式項是頂級的父函式項,再去處理函式主體部分
if depth == 0 { // 步骤四
reduce_inner(r, depth)
} else {
r
}
}
| _ =>
if has_unreduced_functon(m) { // 步骤二
// 若左閉項尚存在未歸約的函式項,則先歸約左閉項
let ma = reduce_inner(m, depth + 1)
reduce_inner(App(ma, n), depth) // 步骤五
} else {
// 徹底歸約左閉項後,再歸約右閉項
App(m, reduce_inner(n, depth))
}
}
}
}
reduce_inner(lambda, 0)
}
爻算式
// λxy.x
let if_then_else = Fun("x", Var("x"))
// λxy.x
let b_true = Fun("x", Fun("y", Var("x")))
// λxy.y
let b_false = Fun("x", Fun("y", Var("y")))
// (if_then_else b_true )MN ==> M
let true_then_m = App(App(App(if_then_else, b_true ), Var("M")), Var("N"))
邱奇数
let zero = Fun("f", Fun("x", Var("x")))
// λfx.fx
let one = Fun("f", Fun("x", App(Var("f"), Var("x"))))
// λfx.f(fx)
let two = Fun("f", Fun("x", App(Var("f"), App(Var("f"), Var("x")))))
// λfx.f(f(fx))
let three = Fun(
"f", Fun("x", App(Var("f"), App(Var("f"), App(Var("f"), Var("x")))))
)
// λfx.f(f(f(fx))
let four = Fun(
"f",
Fun("x", App(Var("f"), App(Var("f"), App(Var("f"), App(Var("f"), Var("x")))))),
)
常用算式
// λn.n(λz.F)T
let if_zero_then_else = Fun("n", App(App(Var("n"), Fun("z", b_false)), b_true))
// λxyz.zxy
let pair = Fun("x", Fun("y", Fun("z", App(App(Var("z"), Var("x")), Var("y")))))
// λp.p(λxy.x)
let first = Fun("p", App(Var("p"), Fun("x", Fun("y", Var("x")))))
// λp.p(λxy.y)
let second = Fun("p", App(Var("p"), Fun("x", Fun("y", Var("y")))))
加一
// λnfx.f(nfx)
let succ = Fun(
"n",
Fun("f", Fun("x", App(Var("f"), App(App(Var("n"), Var("f")), Var("x"))))),
)
减一
let pred_it = Fun(
"p",
App(
App(pair, App(second, Var("p"))),
App(succ, App(second, Var("p"))),
),
)
// pair zero zero
let pair_zero = App(App(pair, zero), zero)
// λn.church_first(n pred_it pair_zero)
let pred = Fun("n", App(first, App(App(Var("n"), pred_it), pair_zero)))
n加m
// λnmfx.nf(mfx)
let add = Fun(
"n",
Fun(
"m",
Fun("f",
Fun("x", App(App(Var("n"), Var("f")), App(App(Var("m"), Var("f")), Var("x"))))
),
),
)
n减m
let minus = Fun("n", Fun("m", App(App(Var("m"), pred), Var("n"))))
n乘m,非YF算式,两种方式,第一种是PPT上的算法
// λu.(add u m) u即为bottom值
let multi_it = Fun("u", App(App(add, Var("u")), Var("m")))
// λnm.(if_zero_then_else n) zero (n multi_it zero) // PPT写的模式
let multi = Fun(
"n",
Fun(
"m",
App(
App(App(if_zero_then_else, Var("n")), zero),
App(App(Var("n"), multi_it), zero),
),
),
)
// λx.mfx
let multi_it2 = Fun("x", App(App(Var("m"), Var("f")), Var("x")))
// λnmfx.(n multi_it2) x
let multi2 = Fun(
"n",
Fun("m", Fun("f", Fun("x", App(App(Var("n"), multi_it2), Var("x"))))),
)
两个经典无限算子
// λx.xx
let combinator_w = Fun("x", App(Var("x"), Var("x")))
// λF.(combinator_w λf.F(combinator_w f))
let combinator_Y = Fun("F", App(combinator_w, Fun("f", App(Var("F"), App(combinator_w, Var("f"))))))
两种无限算子模式的邱奇乘法
// combinator_w (λfnm.(if_zero_then_else n) zero (add m (combinator_w f (pred n) m)))
let multi_wF = App(
combinator_w,
Fun(
"f",
Fun(
"n",
Fun(
"m",
App(
App(App(if_zero_then_else, Var("n")), church_zero),
App(
App(add, Var("m")),
App(App(App(combinator_w, Var("f")), App(pred, Var("n"))), Var("m")),
),
),
),
),
),
)
// λfnm.(if_zero_then_else n) zero (add m (f (pred n) m))
let church_multi_F = Fun(
"f",
Fun(
"n",
Fun(
"m",
App(
App(App(if_zero_then_else, Var("n")), zero),
App(App(add, Var("m")), App(App(Var("f"), App(pred, Var("n"))), Var("m"))),
),
),
),
)
let multi_YF = App(combinator_Y, multi_F)
假设测试用例为App(App(App(combinator_Y, multi_F)two)two)
// 待补充
常規測試
用例 (λx.x)(λx.x) ==> λx.x
輸入 (λx.x) (λx.x)
輸出 λx.x
用例 (λx.x(λz.z))(λy.y) ==> λz.z
輸入 (λx.x (λz.z)) (λy.y)
輸出 λz.z
用例 (λyx.xy)(λyx.xy) ==> λx.x(λyx.xy)
輸入 (λy.λx.x y) (λy.λx.x y)
輸出 λx.x (λy.λx.x y)
用例 (λxxy.xy)(xy) ==> λxy.xy
輸入 (λx.λx.λy.x y) (x y)
輸出 λx.λy.x y
用例 (λxyz.yz)(xy) ==> λyz.yz
輸入 (λx.λy.λz.y z) (x y)
輸出 λy.λz.y z
自由變量測試
分支 x[N/x] = N
用例 (λx.x)(xy) ==> xy
輸入 (λx.x) (x y)
輸出 x y
分支 y[N/x] = y, if x != y
用例 (λx.y)((λz.zz)(λw.w)) ==> y
輸入 (λx.y) ((λz.z z) (λw.w))
輸出 y
分支 (MP)[N/x] = (M[N/x])(P[N/x])
用例 (λx.(λx.x)x)y ==> y
輸入 (λx.(λx.x) x) y
輸出 y
用例 (λx.x(λxz.xw))(abc) ==> abc(λxz.xw))
輸入 (λx.x (λx.λz.x w)) (a b c)
輸出 a b c (λx.λz.x w)
分支 (λx.M)[N/x] = λx.M
用例 (λxx.xyz)(xzw) ==> λx.xyz
輸入 (λx.λx.x z w) (x z w)
輸出 λx.x z w
分支 (λy.M)[N/x] = λy.(M[N/x]), if x != y and y 非屬 FV(N)
用例 (λxy.xy)(xzw) ==> λy.xzwy
輸入 (λx.λy.x y) (x z w)
輸出 λy.x z w y
分支 (λy.M)[N/x] = λy'.((M[y'/y])[N/x]), if x != y and y 屬 FV(N) and (y' or y'') 非屬 FV(N)
用例 (λxy.xy)(xy) ==> λy'.xyy'
輸入 (λx.λy.x y) (x y)
輸出 λy'.x y y'
用例 (λxy.xy)(yx) ==> λy'.yxy'
輸入 (λx.λy.x y) (y x)
輸出 λy'.y x y'
用例 (λxy.yx)(yx) ==> λy'.y'(yx)
輸入 (λx.λy.y x) (y x)
輸出 λy'.y' (y x)
用例 (λxyy'.xy)(xy) ==> λy''y'.xyy''
輸入 (λx.λy.λy'.x y) (x y)
輸出 λy''.λy'.x y y''
用例 (λxy'y.xy)(xy) ==> λy'y''.xyy''
輸入 (λx.λy'.λy.x y) (x y)
輸出 λy'.λy''.x y y''
用例 (λxy'y.yx)(yx) ==> λy'y''.y''(yx)
輸入 (λx.λy'.λy.y x) (y x)
輸出 λy'.λy''.y'' (y x)
用例 (λxyz.xy)(xyz) ==> λy'z'.xyzy'
輸入 (λx.λy.λz.x y) (x y z)
輸出 λy'.λz'.x y z y'
用例 (λxy.xy)(λz.yz) ==> λy'.yy'
輸入 (λx.λy.x y) (λz.y z)
輸出 λy'.y y'
用例 (λxx'x''.xx'x'')(xx'x'') ==> λx'''x''''.xx'x''x'''x''''
輸入 (λx.λx'.λx''.x x' x'') (x x' x'')
輸出 λx'''.λx''''.x x' x'' x''' x''''
邱奇測試
用例 (if_then_else condition_true)MN ==> M
輸入 (λx.x) (λx.λy.x) M N
輸出 M
用例 (if_then_else condition_false)MN ==> N
輸入 (λx.x) (λx.λy.y) M N
輸出 N
用例 church_succ 0 ==> 1
輸入 (λn.λf.λx.f (n f x)) (λf.λx.x)
輸出 λf.λx.f x
用例 church_succ 3 ==> 4
輸入 (λn.λf.λx.f (n f x)) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f (f (f x)))
用例 church_add 2 + 1 ==> 3
輸入 (λn.λm.λf.λx.n f (m f x)) (λf.λx.f (f x)) (λf.λx.f x)
輸出 λf.λx.f (f (f x))
用例 church_add 2 + 3 ==> 5
輸入 (λn.λm.λf.λx.n f (m f x)) (λf.λx.f (f x)) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f (f (f (f x))))
用例 church_minus 5 - 2 ==> 3
輸入 (λn.λm.m (λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) n) (λf.λx.f (f (f (f (f x))))) (λf.λx.f (f x))
輸出 λf.λx.f (f (f x))
用例 church_minus 5 - 3 ==> 2
輸入 (λn.λm.m (λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) n) (λf.λx.f (f (f (f (f x))))) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f x)
用例 church_zero_switch 2 ==> F
輸入 (λn.n (λz.λx.λy.y) (λx.λy.x)) (λf.λx.f (f x))
輸出 λx.λy.y
用例 church_zero_switch 0 ==> T
輸入 (λn.n (λz.λx.λy.y) (λx.λy.x)) (λf.λx.x)
輸出 λx.λy.x
用例 church_pred 4 ==> 3
輸入 (λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) (λf.λx.f (f (f (f x))))
輸出 λf.λx.f (f (f x))
用例 church_second (church_pair church_zero church_zero)
輸入 (λp.(λp.p (λx.λy.y)) p) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x))
輸出 λf.λx.x
用例 church_multi 4 × 3 ==> 12
輸入 (λn.λm.(λn.n (λz.λx.λy.y) (λx.λy.x)) n (λf.λx.x) (n (λu.(λn.λm.λf.λx.n f (m f x)) u m) (λf.λx.x))) (λf.λx.f (f (f (f x)))) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f (f (f (f (f (f (f (f (f (f (f x)))))))))))
用例 church_multi2 4 × 3 ==> 12
輸入 (λn.λm.λf.λx.n (λx.m f x) x) (λf.λx.f (f (f (f x)))) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f (f (f (f (f (f (f (f (f (f (f x)))))))))))
用例 church_multi_wF 4 × 3 ==> 12
輸入 (λx.x x) (λf.λn.λm.(λn.n (λz.λx.λy.y) (λx.λy.x)) n (λf.λx.x) ((λn.λm.λf.λx.n f (m f x)) m ((λx.x x) f ((λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) n) m))) (λf.λx.f (f (f (f x)))) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f (f (f (f (f (f (f (f (f (f (f x)))))))))))
用例 church_multi_YF 4 × 3 ==> 12
輸入 (λF.(λx.x x) (λf.F ((λx.x x) f))) (λf.λn.λm.(λn.n (λz.λx.λy.y) (λx.λy.x)) n (λf.λx.x) ((λn.λm.λf.λx.n f (m f x)) m (f ((λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) n) m))) (λf.λx.f (f (f (f x)))) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f (f (f (f (f (f (f (f (f (f (f x)))))))))))
用例 church_factorial_wF 3 ==> 6
輸入 (λx.x x) (λf.λn.(λn.n (λz.λx.λy.y) (λx.λy.x)) n (λf.λx.f x) ((λx.x x) (λf.λn.λm.(λn.n (λz.λx.λy.y) (λx.λy.x)) n (λf.λx.x) ((λn.λm.λf.λx.n f (m f x)) m ((λx.x x) f ((λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) n) m))) n ((λx.x x) f ((λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) n)))) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f (f (f (f (f x)))))
用例 church_factorial_YF 3 ==> 6
輸入 (λF.(λx.x x) (λf.F ((λx.x x) f))) (λf.λn.(λn.n (λz.λx.λy.y) (λx.λy.x)) n (λf.λx.f x) ((λx.x x) (λf.λn.λm.(λn.n (λz.λx.λy.y) (λx.λy.x)) n (λf.λx.x) ((λn.λm.λf.λx.n f (m f x)) m ((λx.x x) f ((λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) n) m))) n (f ((λn.(λp.p (λx.λy.x)) (n (λp.(λx.λy.λz.z x y) ((λp.p (λx.λy.y)) p) ((λn.λf.λx.f (n f x)) ((λp.p (λx.λy.y)) p))) ((λx.λy.λz.z x y) (λf.λx.x) (λf.λx.x)))) n)))) (λf.λx.f (f (f x)))
輸出 λf.λx.f (f (f (f (f (f x)))))
open Belt
type rec lambda =
| Var(string)
| Fun(string, lambda)
| App(lambda, lambda)
let print_lambda = l => {
let print_paren = (b, s) => {
if b {
"(" ++ s ++ ")"
} else {
s
}
}
let rec go = (l, p) => {
switch l {
| Var(x) => x
| Fun(x, a) => print_paren(p > 0, "λ" ++ x ++ "." ++ go(a, 0))
| App(a, b) => print_paren(p > 1, go(a, 1) ++ " " ++ go(b, 2))
}
}
go(l, 0)
}
// 取函式項完整參數名集合
let rec get_parameters = lambda => {
switch lambda {
| Fun(x, body) => List.concatMany([list{x}, get_parameters(body)])
| _ => list{}
}
}
// 取閉項自由變量名集合
let rec get_free_variables = lambda => {
switch lambda {
| Var(x) => list{x}
| Fun(x, body) => get_free_variables(body)->List.keep(e => e != x)
| App(m, n) =>
let list = List.concatMany([get_free_variables(m), get_free_variables(n)])
let set = Set.String.fromArray(list->List.toArray)
set->Set.String.toList
}
}
// 修改變量名,並保證與函式項參數名集合不相衝突
let fresh_name = (x, function_variables) => {
let rec fresh_name_inner = x => {
let new_x = x ++ "'"
if function_variables->List.has(new_x, String.equal) {
fresh_name_inner(new_x)
} else {
new_x
}
}
fresh_name_inner(x)
}
// body項的自由變量名集合是否包含x變量名
let has_free_variable = (body, x) => get_free_variables(body)->List.has(x, String.equal)
// 全局替換閉項的某個變量名
let rename = (lambda, old, new) => {
let rec go = lambda => {
switch lambda {
| Var(x) =>
if x == old {
Var(new)
} else {
lambda
}
| Fun(x, body) =>
if x == old {
Fun(new, go(body))
} else {
Fun(x, go(body))
}
| App(m, n) => App(go(m), go(n))
}
}
go(lambda)
}
// 歸約替換
let rec substitution = (x, va, body, parameters) => {
let (v, fv) = va
switch body {
| Var(y) =>
if y == x {
v
} else {
body
}
| Fun(p, lambda) =>
if x == p {
body
} else if fv->List.has(p, String.equal) {
// 傳入值的自由變量名集合跟函式項的p參數名發生衝突時,則進行相關處理
let new_p = fresh_name(p, parameters)
let new_lambda = rename(lambda, p, new_p)
Fun(new_p, substitution(x, va, new_lambda, list{new_p, ...parameters}))
} else {
Fun(p, substitution(x, va, lambda, parameters))
}
| App(m, n) => {
/*
* 若歸約函式項主體的調用鏈上,存在着局部子函式項,則取該子函式項的參數名集合,
* 以避免歸約該子函式項時,受到原父歸約函式項參數名的污染
*/
let m_parameters = switch m {
| Fun(_, _) => get_parameters(m)
| _ => parameters
}
let n_parameters = switch n {
| Fun(_, _) => get_parameters(n)
| _ => parameters
}
let m' = substitution(x, va, m, m_parameters)
let n' = substitution(x, va, n, n_parameters)
App(m', n')
}
}
}
// 此閉項是否存在函式項
let rec has_unreduced_functon = lambda =>
switch lambda {
| App(m, _) =>
switch m {
| Fun(_, _) => true
| _ => has_unreduced_functon(m)
}
| _ => false
}
let reduce = lambda => {
let rec reduce_inner = (lambda, depth) => {
switch lambda {
| Var(_) => lambda
| Fun(x, body) => Fun(x, reduce_inner(body, 0))
| App(m, n) =>
// 閉項調用鏈處理
switch m {
| Fun(x, body) => {
// 對受控函式項進行歸約,Call by value
let r = if has_free_variable(body, x) {
let parameters = get_parameters(m)
let fv = get_free_variables(n)
let v = switch n {
// w演算時,函式項需延遲處理,不然會無限循環
| Fun(_, _) => n
| _ => reduce_inner(n, depth)
}
substitution(x, (v, fv), body, parameters)
} else {
body
}
// 若此函式項是頂級的父函式項,再去處理函式主體部分
if depth == 0 {
reduce_inner(r, depth)
} else {
r
}
}
| _ =>
if has_unreduced_functon(m) {
// 若左閉項尚存在未歸約的函式項,則先歸約左閉項
let ma = reduce_inner(m, depth + 1)
reduce_inner(App(ma, n), depth)
} else {
// 徹底歸約左閉項後,再歸約右閉項
App(m, reduce_inner(n, depth))
}
}
}
}
reduce_inner(lambda, 0)
}
// λxy.x
let if_then_else = Fun("x", Var("x"))
// λxy.x
let condition_true = Fun("x", Fun("y", Var("x")))
// λxy.y
let condition_false = Fun("x", Fun("y", Var("y")))
// λfx.x
let church_zero = Fun("f", Fun("x", Var("x")))
// λfx.fx
let church_one = Fun("f", Fun("x", App(Var("f"), Var("x"))))
// λfx.f(fx)
let church_two = Fun("f", Fun("x", App(Var("f"), App(Var("f"), Var("x")))))
// λfx.f(f(fx))
let church_three = Fun("f", Fun("x", App(Var("f"), App(Var("f"), App(Var("f"), Var("x"))))))
// λfx.f(f(f(fx))
let church_four = Fun(
"f",
Fun("x", App(Var("f"), App(Var("f"), App(Var("f"), App(Var("f"), Var("x")))))),
)
// λfx.f(f(f(f(fx))
let church_five = Fun(
"f",
Fun("x", App(Var("f"), App(Var("f"), App(Var("f"), App(Var("f"), App(Var("f"), Var("x"))))))),
)
// λnfx.f(nfx)
let church_succ = Fun(
"n",
Fun("f", Fun("x", App(Var("f"), App(App(Var("n"), Var("f")), Var("x"))))),
)
// λnmfx.nf(mfx)
let church_add = Fun(
"n",
Fun(
"m",
Fun("f", Fun("x", App(App(Var("n"), Var("f")), App(App(Var("m"), Var("f")), Var("x"))))),
),
)
// λn.n(λz.F)T
let church_zero_switch = Fun("n", App(App(Var("n"), Fun("z", condition_false)), condition_true))
// λxyz.zxy
let church_pair = Fun("x", Fun("y", Fun("z", App(App(Var("z"), Var("x")), Var("y")))))
// λp.p(λxy.x)
let church_first = Fun("p", App(Var("p"), Fun("x", Fun("y", Var("x")))))
// λp.p(λxy.y)
let church_second = Fun("p", App(Var("p"), Fun("x", Fun("y", Var("y")))))
// λp.church_pair(church_second p)(church_succ(church_second p))
let church_pred_it = Fun(
"p",
App(
App(church_pair, App(church_second, Var("p"))),
App(church_succ, App(church_second, Var("p"))),
),
)
// church_pair church_zero church_zero
let church_pair_zero = App(App(church_pair, church_zero), church_zero)
// λn.church_first(n church_pred_it church_pair_zero)
let church_pred = Fun("n", App(church_first, App(App(Var("n"), church_pred_it), church_pair_zero)))
// λnmfx.(m church_pred)nfx
let church_minus = Fun("n", Fun("m", App(App(Var("m"), church_pred), Var("n"))))
// λu.(church_add u m)
let church_multi_it = Fun("u", App(App(church_add, Var("u")), Var("m")))
// λnm.(church_zero_switch n) church_zero (n church_multi_it church_zero)
let church_multi = Fun(
"n",
Fun(
"m",
App(
App(App(church_zero_switch, Var("n")), church_zero),
App(App(Var("n"), church_multi_it), church_zero),
),
),
)
// λx.mfx
let church_multi_it2 = Fun("x", App(App(Var("m"), Var("f")), Var("x")))
// λnmfx.(n church_multi_it2) x
let church_multi2 = Fun(
"n",
Fun("m", Fun("f", Fun("x", App(App(Var("n"), church_multi_it2), Var("x"))))),
)
// λx.xx
let combinator_w = Fun("x", App(Var("x"), Var("x")))
// λF.(combinator_w λf.F(combinator_w f))
let combinator_Y = Fun("F", App(combinator_w, Fun("f", App(Var("F"), App(combinator_w, Var("f"))))))
// combinator_w (λfnm.(church_zero_switch n) church_zero (church_add m (combinator_w f (church_pred n) m)))
let church_multi_wF = App(
combinator_w,
Fun(
"f",
Fun(
"n",
Fun(
"m",
App(
App(App(church_zero_switch, Var("n")), church_zero),
App(
App(church_add, Var("m")),
App(App(App(combinator_w, Var("f")), App(church_pred, Var("n"))), Var("m")),
),
),
),
),
),
)
// λfnm.(church_zero_switch n) church_zero (church_add m (f (church_pred n) m))
let church_multi_F = Fun(
"f",
Fun(
"n",
Fun(
"m",
App(
App(App(church_zero_switch, Var("n")), church_zero),
App(App(church_add, Var("m")), App(App(Var("f"), App(church_pred, Var("n"))), Var("m"))),
),
),
),
)
let church_multi_YF = App(combinator_Y, church_multi_F)
// combinator_w (λfn.(church_zero_switch n) church_one (church_multi_wF n (combinator_w f (church_pred n))))
let church_factorial_wF = App(
combinator_w,
Fun(
"f",
Fun(
"n",
App(
App(App(church_zero_switch, Var("n")), church_one),
App(
App(church_multi_wF, Var("n")),
App(App(combinator_w, Var("f")), App(church_pred, Var("n"))),
),
),
),
),
)
// λfn.(church_zero_switch n) church_one ((Y church_multi_F) n (f (church_pred n)))
let church_factorial_F = Fun(
"f",
Fun(
"n",
App(
App(App(church_zero_switch, Var("n")), church_one),
App(App(church_multi_wF, Var("n")), App(Var("f"), App(church_pred, Var("n")))),
),
),
)
let church_factorial_YF = App(combinator_Y, church_factorial_F)
type case_pair = {
case: string,
lambda: lambda,
}
let normal_lambdas = list{
{
case: "(λx.x)(λx.x) ==> λx.x",
lambda: App(Fun("x", Var("x")), Fun("x", Var("x"))),
},
{
case: "(λx.x(λz.z))(λy.y) ==> λz.z",
lambda: App(Fun("x", App(Var("x"), Fun("z", Var("z")))), Fun("y", Var("y"))),
},
{
case: "(λyx.xy)(λyx.xy) ==> λx.x(λyx.xy)",
lambda: App(
Fun("y", Fun("x", App(Var("x"), Var("y")))),
Fun("y", Fun("x", App(Var("x"), Var("y")))),
),
},
{
case: "(λxxy.xy)(xy) ==> λxy.xy",
lambda: App(Fun("x", Fun("x", Fun("y", App(Var("x"), Var("y"))))), App(Var("x"), Var("y"))),
},
{
case: "(λxyz.yz)(xy) ==> λyz.yz",
lambda: App(Fun("x", Fun("y", Fun("z", App(Var("y"), Var("z"))))), App(Var("x"), Var("y"))),
},
}
let church_lambdas = list{
// Boolean Definition
{
case: "(if_then_else condition_true)MN ==> M",
lambda: App(App(App(if_then_else, condition_true), Var("M")), Var("N")),
},
{
case: "(if_then_else condition_false)MN ==> N",
lambda: App(App(App(if_then_else, condition_false), Var("M")), Var("N")),
},
{
case: "church_succ 0 ==> 1",
lambda: App(church_succ, church_zero),
},
{
case: "church_succ 3 ==> 4",
lambda: App(church_succ, church_three),
},
{
case: "church_add 2 + 1 ==> 3",
lambda: App(App(church_add, church_two), church_one),
},
{
case: "church_add 2 + 3 ==> 5",
lambda: App(App(church_add, church_two), church_three),
},
{
case: "church_minus 5 - 2 ==> 3",
lambda: App(App(church_minus, church_five), church_two),
},
{
case: "church_minus 5 - 3 ==> 2",
lambda: App(App(church_minus, church_five), church_three),
},
{
case: "church_zero_switch 2 ==> F",
lambda: App(church_zero_switch, church_two),
},
{
case: "church_zero_switch 0 ==> T",
lambda: App(church_zero_switch, church_zero),
},
{
case: "church_pred 4 ==> 3",
lambda: App(church_pred, church_four),
},
{
case: "church_second (church_pair church_zero church_zero)",
lambda: App(
Fun("p", App(church_second, Var("p"))),
App(App(church_pair, church_zero), church_zero),
),
},
{
case: "church_multi 4 × 3 ==> 12",
lambda: App(App(church_multi, church_four), church_three),
},
{
case: "church_multi2 4 × 3 ==> 12",
lambda: App(App(church_multi2, church_four), church_three),
},
{
case: "church_multi_wF 4 × 3 ==> 12",
lambda: App(App(church_multi_wF, church_four), church_three),
},
{
case: "church_multi_YF 4 × 3 ==> 12",
lambda: App(App(church_multi_YF, church_four), church_three),
},
{
case: "church_factorial_wF 3 ==> 6",
lambda: App(church_factorial_wF, church_three),
},
{
case: "church_factorial_YF 3 ==> 6",
lambda: App(church_factorial_YF, church_three),
},
}
type branch_pair = {
branch: string,
cases: list<case_pair>,
}
let free_variables_lambdas = list{
{
branch: "x[N/x] = N",
cases: list{
{
case: "(λx.x)(xy) ==> xy",
lambda: App(Fun("x", Var("x")), App(Var("x"), Var("y"))),
},
},
},
{
branch: "y[N/x] = y, if x != y",
cases: list{
{
case: "(λx.y)((λz.zz)(λw.w)) ==> y",
lambda: App(Fun("x", Var("y")), App(Fun("z", App(Var("z"), Var("z"))), Fun("w", Var("w")))),
},
},
},
{
branch: "(MP)[N/x] = (M[N/x])(P[N/x])",
cases: list{
{
case: "(λx.(λx.x)x)y ==> y",
lambda: App(Fun("x", App(Fun("x", Var("x")), Var("x"))), Var("y")),
},
{
case: "(λx.x(λxz.xw))(abc) ==> abc(λxz.xw))",
lambda: App(
Fun("x", App(Var("x"), Fun("x", Fun("z", App(Var("x"), Var("w")))))),
App(App(Var("a"), Var("b")), Var("c")),
),
},
},
},
{
branch: "(λx.M)[N/x] = λx.M",
cases: list{
{
case: "(λxx.xyz)(xzw) ==> λx.xyz",
lambda: App(
Fun("x", Fun("x", App(App(Var("x"), Var("z")), Var("w")))),
App(App(Var("x"), Var("z")), Var("w")),
),
},
},
},
{
branch: "(λy.M)[N/x] = λy.(M[N/x]), if x != y and y 非屬 FV(N)",
cases: list{
{
case: "(λxy.xy)(xzw) ==> λy.xzwy",
lambda: App(
Fun("x", Fun("y", App(Var("x"), Var("y")))),
App(App(Var("x"), Var("z")), Var("w")),
),
},
},
},
{
branch: "(λy.M)[N/x] = λy'.((M[y'/y])[N/x]), if x != y and y 屬 FV(N) and (y' or y'') 非屬 FV(N)",
cases: list{
{
case: "(λxy.xy)(xy) ==> λy'.xyy'",
lambda: App(Fun("x", Fun("y", App(Var("x"), Var("y")))), App(Var("x"), Var("y"))),
},
{
case: "(λxy.xy)(yx) ==> λy'.yxy'",
lambda: App(Fun("x", Fun("y", App(Var("x"), Var("y")))), App(Var("y"), Var("x"))),
},
{
case: "(λxy.yx)(yx) ==> λy'.y'(yx)",
lambda: App(Fun("x", Fun("y", App(Var("y"), Var("x")))), App(Var("y"), Var("x"))),
},
{
case: "(λxyy'.xy)(xy) ==> λy''y'.xyy''",
lambda: App(
Fun("x", Fun("y", Fun("y'", App(Var("x"), Var("y"))))),
App(Var("x"), Var("y")),
),
},
{
case: "(λxy'y.xy)(xy) ==> λy'y''.xyy''",
lambda: App(
Fun("x", Fun("y'", Fun("y", App(Var("x"), Var("y"))))),
App(Var("x"), Var("y")),
),
},
{
case: "(λxy'y.yx)(yx) ==> λy'y''.y''(yx)",
lambda: App(
Fun("x", Fun("y'", Fun("y", App(Var("y"), Var("x"))))),
App(Var("y"), Var("x")),
),
},
{
case: "(λxyz.xy)(xyz) ==> λy'z'.xyzy'",
lambda: App(
Fun("x", Fun("y", Fun("z", App(Var("x"), Var("y"))))),
App(App(Var("x"), Var("y")), Var("z")),
),
},
{
case: "(λxy.xy)(λz.yz) ==> λy'.yy'",
lambda: App(Fun("x", Fun("y", App(Var("x"), Var("y")))), Fun("z", App(Var("y"), Var("z")))),
},
{
case: "(λxx'x''.xx'x'')(xx'x'') ==> λx'''x''''.xx'x''x'''x''''",
lambda: App(
Fun("x", Fun("x'", Fun("x''", App(App(Var("x"), Var("x'")), Var("x''"))))),
App(App(Var("x"), Var("x'")), Var("x''")),
),
},
},
},
}
let testSuit = pairs => {
pairs->List.forEach(pair => {
let {case, lambda} = pair
Js.log("用例\t" ++ case)
Js.log("輸入\t" ++ print_lambda(lambda))
let reduction = reduce(lambda)
Js.log("輸出\t" ++ print_lambda(reduction))
Js.log("")
})
}
let testSuits = suits => {
suits->List.forEach(suit => {
let {branch, cases} = suit
Js.log("分支\t" ++ branch)
testSuit(cases)
})
}
Js.log("常規測試")
testSuit(normal_lambdas)
Js.log("自由變量測試")
testSuits(free_variables_lambdas)
Js.log("邱奇測試")
testSuit(church_lambdas)
已看过博主的文章,很不错的内容,干货满满,期望师傅能输出更多干货,并强烈为师傅分享自己的知识点赞
另外,如果可以的话,期待师傅能给正在参加年度博客之星评选的我一个五星好评,您的五星好评都是对我的支持与鼓励:https://bbs.csdn.net/topics/611387568
点赞五星好评回馈小福利:抽奖赠书 | 总价值200元,书由君自行挑选(从此页面参与抽奖的同学,只需五星好评后,参与抽奖)