[基础软件理论与实践] 第二节作业实现 PerfectPan??

PerfectPan?? 2022-11-28 00:29:21

作业信息

  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

type rec lambda =
  | Var(string)
  | Fn(string, lambda)
  | App(lambda, lambda)

// copy from lec2-code/src/Lambda.res
let print_lambda = l => {
  let print_paren = (b, s) => {
    if b {
      "(" ++ s ++ ")"
    } else {
      s
    }
  }
  let rec go = (l, p) => {
    switch l {
    | Var(x) => x
    | Fn(x, a) => print_paren(p > 0, "fun " ++ x ++ " -> " ++ go(a, 0))
    | App(a, b) => print_paren(p > 1, go(a, 1) ++ " " ++ go(b, 2))
    }
  }
  go(l, 0)
}

let rec acquireFreeVar = va => {
  switch va {
  | Var(x) => list{x}
  | App(m, n) => Belt.List.concat(acquireFreeVar(m), acquireFreeVar(n))
  | Fn(x, body) => Belt.List.keep(acquireFreeVar(body), y => y != x)
  }
}

let rec genNewName = (oldName, freeVar) => {
  if Belt.List.has(freeVar, oldName ++ "a", String.equal) {
    genNewName(oldName ++ "a", freeVar)
  } else {
    oldName ++ "a"
  }
}

// substitution function a[v/x]
let rec subst = (x, v, a, freeVar) => {
  switch a {
  | Var(y) =>
    if x == y {
      v
    } else {
      a
    }
  | App(f, arg) => App(subst(x, v, f, freeVar), subst(x, v, arg, freeVar))
  | Fn(y, body) =>
    if x == y {
      a
      // 不相等说明要把 body 里是 x 的给替换掉,如果 freeVar 里有值等于 y,要把 y rename 了
    } else if Belt.List.has(freeVar, y, String.equal) {
      let newName = genNewName(y, freeVar)
      let newBody = subst(y, Var(newName), body, list{newName})
      Fn(newName, subst(x, v, newBody, freeVar))
    } else {
      Fn(y, subst(x, v, body, freeVar))
    }
  }
}

let rec eval = (t: lambda) => {
  switch t {
  // 最后消出来是个 Var 是不允许的
  | Var(_) => assert false
  | Fn(_, _) => t
  | App(f, arg) => {
      let Fn(x, body) = eval(f)
      let va = eval(arg)
      let freeVar = acquireFreeVar(va)
      eval(subst(x, va, body, freeVar))
    }
  }
}

let test1 = Fn("x", Var("x"))
let test2 = App(Fn("x", Var("x")), Fn("x", Var("x")))
let test3 = App(
  Fn("y", Fn("x", App(Var("x"), Var("y")))),
  Fn("y", Fn("x", App(Var("x"), Var("y")))),
)
let test4 = App(
  App(Fn("y", Fn("x", App(Var("x"), Var("y")))), Fn("y", Fn("x", App(Var("x"), Var("y"))))),
  Fn("z", Var("z")),
)
let test5 = App(Fn("u", App(Var("u"), Fn("y", App(Var("y"), Var("z"))))), Fn("z", Var("z")))

Js.log(print_lambda(test1))
Js.log(print_lambda(eval(test1)))

Js.log(print_lambda(test2))
Js.log(print_lambda(eval(test2)))

Js.log(print_lambda(eval(Fn("z", App(Fn("x", Var("x")), Var("y"))))))
Js.log(print_lambda(test3))
Js.log(print_lambda(eval(test3)))

Js.log(print_lambda(test4))
Js.log(print_lambda(eval(test4)))

Js.log(print_lambda(test5))
Js.log(print_lambda(eval(test5)))

任务 3

// Homework: implement the arithmetic functions for peano numbers
let rec peano_add = (n: nat, m: nat): nat => {
  switch n {
  | Z => m
  // hint: use peano_succ
  | S(n') => peano_add(n', S(m))
  }
}
let rec peano_mul = (n: nat, m: nat): nat => {
  switch n {
  | Z => Z
  // hint: use peano_succ
  | S(n') => peano_add(m, peano_mul(n', m))
  }
}

// Homework: implement the arithmetic functions for church numbers
let church_add = (n: cnum<_>, m: cnum<_>): cnum<_> => {
  (s, z) => n(s, m(s, z))
}
let church_mul = (n: cnum<_>, m: cnum<_>): cnum<_> => {
  (s, z) => n((z) => m(s, z), z)
}

 

...全文
80 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
PerfectPan?? 2022-11-28
  • 打赏
  • 举报
回复

slides 中提到我们可以用 beta-reduction 一直对 lambda 式子进行化简,但目前的 interpreter 应该不会针对 Fn(_, body) 的场景下的 body 内部继续进行 substitution,是不是这个 eval 只是针对一次 App 的结果求值,如果要完成最终的化简要怎么做呢

230

社区成员

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

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