我们在这章主要使用OCaml来进行代码实现。
4.1 Syntax
我们的第一个工作是定义term。
type term =
TmTrue of info
| TmFalse of info
| TmIf of info * term * term * term
| TmZero of info
| TmSucc of info * term
| TmPred of info * term
| TmIsZero of info * term
构造子TmTrue到TmIsZero命名了抽象语法书的不同类型节点,of后面的类型指定了子树的个数。
每个抽象语法树节点都被注解为一个类型info的值,它用来向用户展示哪里出现错误。为了理解求值以及类型检查的基本算法,这个信息可以直接被忽略。
在求值关系的定义中,我们需要检查一个term是否为数值。
let rec isnumericval t = match t with
TmZero(_) ->true
| TmSucc(_,t1) -> isnumericval t1
| _ -> false
这是在OCaml中通过模式匹配定义递归函数的典型例子。
检查一个term是否为value的函数如下:
let rec isval t = match t with
TmTrue(_) -> true
| TmFalse(_) -> true
| t when isnumericval t -> true
| _ -> false
其中第三个条款是条件模式:匹配任何term t,但只有当布尔表达式输出true的时候。
4.2 求值
我们在这里直接定义异常,如果没有求值规则能应用。
exception NoRuleApplies
let rec eval1 t = match t with
TmIf(_,TmTrue(_),t2,t3) -> t2
| TmIf(_,TmFalse(_),t2,t3) -> t3
| TmIf(fi, t1,t2,t3) ->
let t1' = eval t1 in
TmIf(fi,t1',t2,t3)
| TmSucc(fi,t1) ->
let t1' = eval1 t1 in
TmSucc(fi, t1')
| TmPred(_, TmZero(_)) ->
TmZero(dummyinfo)
| TmPred(_,TmSucc(_,nv1)) when (isnumericval nv1) →
nv1
| TmPred(fi,t1) →
let t1’ = eval1 t1 in
TmPred(fi, t1’)
| TmIsZero(_,TmZero(_)) →
TmTrue(dummyinfo)
| TmIsZero(_,TmSucc(_,nv1)) when (isnumericval nv1) →
TmFalse(dummyinfo)
| TmIsZero(fi,t1) →
let t1’ = eval1 t1 in
TmIsZero(fi, t1’)
| _ →
raise NoRuleApplies
我们可以定义一个求值函数
let rec eval t =
try let t' = eval1 t
in eval t'
with NoRuleApplied -> t
4.3 The rest of the story
下图为解释器的处理流程: