[基础软件理论与实践] 第二节作业实现(採石)

採石 2022-12-18 19:34:32

作业信息

  • 课程信息:https://bbs.csdn.net/topics/608593392

  • 第二节作业提交帖:https://bbs.csdn.net/topics/608988912

  1. Implement the substitution function N[v/x] : subst (N: lambda, x: string, v: value) : lambda

  2. Think about how substitution works on arbitrary terms, i.e. N[M/x] where M could contain free variables.

  3. Implement Church numberals and arithmetic functions using lambda calculus

作业实现

任务1&2

实现归约函式(body[va/x]),函式签名为substitution(x, va, body, parameters),其中parameters为此函式参数名集合,用以避免重命名冲突

Var(y)类闭项

 若变量名y与x相同(y==x),即是同x[va/x],故归约为va;否则同y[va/x],故归约为Var(y)

App(m, n)

依归约原则,依次执行m[va/x]n[va/x]

Fun(p, lambda)类闭项

(λp.(lambda))[va/x]

  1. 若参数名p与x相同,即是同(λx.(lambda))[va/x],归约为λx.(lambda)
  2. 若参数名p属FV(va)集合,则p需另命名为非FV(va)集合的变量名,同时需避免parameters集合冲突,归约为λfresh.((lambda{fresh/p})[va/x])
  3. 参数名p不与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')
    }
  }
}

任务3

假设我们传入的lambda是close的,并假设其项式为App(...(((Fun/1->Fun/2->...->Fun/n)N/1)N/2)...)N/n),我们来用语言模拟下程式运行。

App(m, n) // 步骤一

进入App闭项分支。

if has_unreduced_functon(m) // 步骤二

通过判断,存在未被归约的函式项,归约Fun/1->Fun/2

Fun(x, body) // 步骤三

此时闭项的左侧是Fun类闭项,因此进入此分支

Fun/2是函式项,我们采取惰性归约的策略。因为,若Fun/2是omega算式,即(λx.xx)(λx.xx),直接归约会导致程式陷入无限循环

我们设此归约结果为Fun/(1'/2)

if depth == 0 // 步骤四

即当(Fun/1->Fun/2->...->Fun/n)被(N/1 N/2 ... N/n)全部归约彻底时,这是必然的事情,因为我们假设的lambda是close的。

而此时,我们离底部还差m深度个距离,必须直接返回。否则,假如若Fun/1是omega算式,那么,归约Fun/(1'/2)的函式body的结果也必然是无限循环。

depth的计算比较粗略,就是离最外围的括号多少距离。

reduce_inner(App(ma, n), depth) // 步骤五

ma即为步骤三Fun/(1'/2),即步骤四的执行结果,跳出后到达此处,位于步骤二之后。

重复步骤三、步骤四、步骤五,直至(Fun/1->Fun/2->...->Fun/n)被(N/1 N/2 ... N/n)全部归约彻底。

Fun(x, body) // 步骤六

因为是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)

尝试用Y不动点乘法算子式来解释程式代码运行步骤

假设测试用例为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)

 

...全文
224 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
2329JFD 2023-01-04
  • 打赏
  • 举报
回复

已看过博主的文章,很不错的内容,干货满满,期望师傅能输出更多干货,并强烈为师傅分享自己的知识点赞

另外,如果可以的话,期待师傅能给正在参加年度博客之星评选的我一个五星好评,您的五星好评都是对我的支持与鼓励:https://bbs.csdn.net/topics/611387568

点赞五星好评回馈小福利:抽奖赠书 | 总价值200元,书由君自行挑选(从此页面参与抽奖的同学,只需五星好评后,参与抽奖)

231

社区成员

发帖
与我相关
我的任务
社区描述
日程:https://bbs.csdn.net/topics/608593392 主页:https://bobzhang.github.io/courses/ B站: “张宏波的基础软件课程”
rescript开发语言 个人社区 广东省·深圳市
社区管理员
  • raelidea
  • MoonBit月兔
  • 幻灰龙
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧