OCaml and S-expressions

303 阅读2分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

S-Expressions

S-expression(或者为 "symbolic expressions")由McCarthy在他的LISP编程语言的论文上提及。最初是作为一种程序员不能操纵的中间表达形式。下面是几个S-expression的例子:

(if x y z)

(* (+ 2 6 4) 3)

(define (f x) (if (= x 0) 1 (* x (f (- x 1)))))

s-expression 是一种非常简单可以表示结构化的表达式。由于其便利性,经常在编译器或者解释器中用到。上面的三个s-expression例子可以归纳成:

  • Symbols: 例如fif
  • Numbers - Lists: S-expression中的序列用小括号括起来,像(+ 2 6 4)(* (+ 2 6 4) 3)

OCaml 中的S-expression

如何在OCaml中表示S-expression。一种选择是使用字符串

let e1 = "(if x y z)"
let e2 = "(* (+ 2 6 4) 3)"

但是,用这种方式使用起来会很麻烦。我们可以在OCaml中添加一个新的类型来表示S-expression

utop # type s_exp = 
   Sym of string | Num of int | Lst of s_exp list;;

其中, SymNumLst为构造器:用来构造S-expression。构造器后面的of代表这个数据对应的类型。例如,符号ifs_exp中的Sym, 以此类推。Lst用来定义表达式是递归的。 这样, (if x y z)就会表达成

let e1 = Lst [ Sym "if"; Sym "x"; Sym "y"; Sym "z"]

( * ( + 2 6 4 ) 3 )就会表达成

let e2 = Lst [Sym "*"; Lst [Sym "+"; Num 2; Num 6; Num 4]; Num 3]

与字符串表达式相比,这种表示方式显得更加臃肿,但是这种表示方式暗含了s-expression的递归的结构。我们也可以用模式匹配,来进行构造s-expression

utop # let which_construtor (e : s_exp) : string = 
         match e with
         | Sym x -> "a symbol"
         | Num n -> "a number"
         | List l -> "a list";;

例如:

let rec total (e: s_exp) : int =
  match e with
  | Sym _ -> 0
  | Num n -> n
  | Lst l -> List.fold_left ( + ) 0 (List.map total l)

可以思考一下如何在编译器中,实现条件判断

在Javascript 中,条件语句

if(x) {
    return y;
} else {
    return z;
}

在Python中 条件语句

if x:
    return y
else:
    return z