TAPL练习:添加TmPLet

问题描述

本练习是北大本研合上课程编程语言的设计原理的一次上机作业,完整的代码可以参考这里。该课程教材是经典的TAPL,作业要为书中fullsimple类型系统(源码可以在TAPL官网下载)添加一种新的term:TmPLet

通俗一点讲,我们要对这样的语句进行扩展:

let x = y in exp

目前的fullsimple系统只支持x和y为单个变量,我们要修改代码使其支持x和y为tuple(元组),使得我们的新类型系统可以对下面的语句进行求值:

/* Examples for testing */

let {x, y, z} = {true, 1, {2}} in z;
let {x, y, z} = {true, 1, {2}} in (lambda x:Nat. x) y;
let {x, y, z} = let x = 1 in {true, x, {2}} in z;
lambda x:Nat. let {x, y} = {true, 1} in x;
let x = 0 in let {y, z} = {1, 2} in x;
let {y, z} = {1, 2} in let y = 3 in y;

解决方案

练习时语法输出部分已经提前实现

语法

syntax.ml文件中增加TmPLet语法定义:

type term =
  ...
  | TmPLet of info * string list * term * term

let tminfo t = match t with
  ...
  | TmPLed(fi,_,_,_) -> fi

parser.mly中增加:

Term :
  ...
  | LET Pattern EQ Term IN Term
    { fun ctx -> TmPLet($1, $2, $4 ctx, $6 (List.fold_left (fun x y -> addname x y) ctx $2)) }
  Pattern :
    LCURLY MetaVars RCURLY 
    { $2 }
    | LCURLY RCURLY 
    { [] }

输出

syntax.ml中增加打印信息:

let rec printtm_Term outer ctx t = match t with
  ...
  | TmPLet(fi, xs, t1, t2) -> 
     obox0();
     pr "let {";
     let rec print xs = match xs with
       x::x'::rest -> pr x; pr ","; print (x'::rest);
       | x::[] -> pr x;
       | [] -> pr ""; in
       
     print xs;
     pr "} = ";
     printtm_Term false ctx t1;
     print_space(); pr "in"; print_space();
     let ctx' = List.fold_left (fun ctx x -> addname ctx x) ctx xs 
       in printtm_Term false ctx' t2;
     cbox()

求值

求值前我们需要弄清楚一个TmPLet项的结构,回顾一下定义:

TmPLet of info * string list * term * term

对应let x = y in exp的形式,x是一个string列表,exp是完成绑定后需要继续求值的表达式,关键是y,在测试用例中我们发现y是一个大括号包含了一堆东西,在parser.mly中我们可以发现它对应一个TyRecord类型的项:

AType :
  ...
  | LCURLY FieldTypes RCURLY
      { fun ctx ->
          TyRecord($2 ctx 1) }

对于一个TmPLet(fi, xs, t1, t2),求值的思路是:先对t1求值,顺利的话会得到一个TmRecord;接着我们每次从xst1中取第一个元素,展开成一个TmLet,一个例子如下:

   let {x, y} = {true, 1} in x
-> let x = true in let {y} = {1} in x
-> let x = true in let y  = 1 in x 

TmLet的求值是fullsimple已经实现好的,因此也就完成了对TmPLet的求值,具体代码就是在core.ml中增加如下内容:

let rec eval1 ctx t = match t with
  ...
  | TmPLet(fi, xs, t1, t2) when (isval ctx t1) ->
      (match (xs, t1) with
        ([x], TmRecord(fi_, [(l, v)])) -> 
           TmLet(fi, x, v, t2)
      | (x::rest1, TmRecord(fi_, (l, v)::rest2)) -> 
           TmLet(fi, x, v, TmPLet(fi, rest1, TmRecord(fi_, rest2), t2))
      | (_, _) -> raise NoRuleApplies)
  | TmPLet(fi, xs, t1, t2) ->
      let t1' = eval1 ctx t1 in TmPLet(fi, xs, t1', t2)

类型推导

core.ml中增加如下内容:

let rec typeof ctx t =
  | TmPLet(fi, xs, t1, t2) ->
      let tyT1 = typeof ctx t1 in
        let rec typePLet ctx xs' t1' =
            (match (xs', t1') with
                ([x], TyRecord([(l, t)])) -> 
                    let ctx' = addbinding ctx x (VarBind(t)) in         
                    typeShift (-1) (typeof ctx' t2)
            | (x::rest1, TyRecord((l, t)::rest2)) ->
                    let ctx' = addbinding ctx x (VarBind(t)) in
                    typeShift (-1) (typePLet ctx' rest1 (TyRecord(rest2)))
            | (_, _) -> error fi "error in TyPLet")
      in typePLet ctx xs tyT1

写完之后发现有些奇怪的报错,提示我们还要修改syntax.mltmmap函数,照猫画虎增加对TmPLet的处理就好了,在syntax.ml中增加:

let tmmap onvar ontype c t = 
  ...
  | TmPLet(fi, [x], TmRecord(fi_, [(l, t)]), t2) -> 
          walk c (TmLet(fi, x, t, t2))
  | TmPLet(fi, x::rest1, TmRecord(fi_, (l, t)::rest2), t2) ->
          walk c (TmLet(fi, x, t, TmPLet(fi, rest1, TmRecord(fi_, rest2), t2)))

测试

对于开篇的测试语句,运行结果如下:

屏幕快照 2017-03-28 上午10.25.31.png

对于语句let {x, y} = {true} in x,上述代码会输出我们在类型推导时设定的错误信息:error in TyPLet

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 个人笔记,方便自己查阅使用 Py.LangSpec.Contents Refs Built-in Closure ...
    freenik阅读 67,777评论 0 5
  • 第一部分Common Lisp介绍第1章 介绍一下Lisp你在学的时候觉得已经明白了,写的时候更加确信了解了,教别...
    geoeee阅读 3,013评论 5 8
  • 第三章 EVAL标记法 3.1 导引 在进一步深入学习Lisp之前,我们必须切换到一个更加适合的标记法,EVAL标...
    geoeee阅读 2,487评论 0 5
  • 明湖天中波澜轻,邑人争渡彩龙惊。菖蒲飞香浸百脉,角黍献波黑虎灵。灵均遗韵今犹在,举杯雄黄话升平。遗叹死直汨罗上,年...
    蓝海跃阅读 268评论 5 5
  • 网络跟人的距离究竟有多远呢?在网络的世界里,我们习惯于虚拟一个角色,但是在文字里,真性情的人往往把文字当做一个感情...
    易水寒一x阅读 284评论 0 0