我正在尝试为 OCaml 中的解释器实现二叉树操作的扩展。扩展基本上是为了
- {emptytree -> e2, node(id1,id2,id3) -> e3} 的 caseT e1。
为了实现扩展(emptytree、caseT、node),必须相应地扩展表示值的集合。现在变为:ExpVal = Int + Bool + ExpVal 列表 + ExpVal 树
OCaml中表示值的对应实现是:
type ’a tree = Empty | Node of ’a * ’a tree * ’a tree
type exp_val =
| NumVal of int
| BoolVal of bool
| ListVal of exp_val list
| TreeVal of exp_val tree
为此,这里是解释器的存根:
let rec eval : expr -> exp_val ea_result= fun e ->
match e with
| Int n -> return (NumVal n)
...
(*emptytree creates an empty tree*)
| EmptyTree ->
return @@ TreeVal (Empty)
(*creates a new tree with data e1 and left and right subtrees e2 and e3;
if the second or third argument is not a tree, it should produce an error*)
| Node (e1, lte, rte) ->
eval_expr e1 >>= fun v1 ->
eval_expr lte >>=
tree_of_treeVal >>= fun v2 ->
eval_expr rte >>=
tree_of_treeVal >>= fun v3 ->
return @@ TreeVal (Node (v1, v2, v3))
| CaseT (target, emptycase, id1, id2, id3, nodecase) ->
eval_expr target >>=
tree_of_treeVal >>= fun t ->
match t with
| Empty -> eval_expr emptycase
| Node (v1, v2, v3) ->
let ids = [id1; id2; id3] in
let evs = [v1; TreeVal v2; TreeVal v3] in
eval_expr (extend_env_list ids evs) nodecase
emptytree、node 和 caseT 的示例测试用例如下:
# interp "emptytree";;
- : exp_val Proc.Ds.result = Ok (TreeVal Empty)
# interp "node(5, node(6, emptytree , emptytree), emptytree)";;
- : exp_val Proc.Ds.result =
Ok (TreeVal (Node (NumVal 5, Node (NumVal 6, Empty , Empty), Empty )))
# interp "
caseT emptytree of {
emptytree -> emptytree ,
node(a,l,r) -> l
}";;
- : exp_val Proc.Ds.result = Ok (TreeVal Empty)
该扩展的抽象语法节点如下:
type expr =
...
| EmptyTree
| Node of expr*expr*expr
| CaseT of expr*expr*string*string*string*expr
我定义了表达值“TreeVal”并使用以下方法提取 TreeVal 的值:
let tree_of_treeVal = function
| TreeVal t -> return t
| _ -> error "Expected a tree!"
此外,我已经有了一些辅助函数,如下所示:
let extend_env : string -> exp_val -> env ea_result =
fun id v env ->
Ok (ExtendEnv (id, v, env))
let rec extend_env_list =
fun env ids evs ->
match ids, evs with
| [], [] -> Ok (env)
| id::ids, ev::evs -> Ok (extend_env_list (extend_env env id ev) ids evs)
| _, _ -> failwith "extend_env_list: Number of arguments does not match number of parameters!"
但是,当我运行顶层时,它会生成一个有趣的错误:
File "src/interp.ml", line 121, characters 33-48:
121 | eval_expr (extend_env_list ids evs) nodecase
^^^^^^^^^^^^^^^
Error: Unbound value extend_env_list
这对我来说似乎很有趣,因为该功能已经定义。在这一点上,我无法弄清楚如何处理和解决问题。有人能指出如何正确实现这个扩展吗?
Ps1 除了这里的那些东西,我还在这个interpreter.ml 的顶部加载了数据结构(ds.ml)和抽象语法树(ast.ml)文件。
Ps2 这是 ds.ml 中的样子:
(* This file defines expressed values and environments *)
(* operations on expressed values *)
type 'a tree = Empty | Node of 'a * 'a tree * 'a tree
type exp_val =
| NumVal of int
| BoolVal of bool
| ProcVal of string*Ast.expr*env
| UnitVal
| ListVal of exp_val list
| TreeVal of exp_val tree
and
env =
| EmptyEnv
| ExtendEnv of string*exp_val*env
(* Environment Abstracted Result *)
type 'a result = Ok of 'a | Error of string
type 'a ea_result = env -> 'a result
let return (v:'a) : 'a ea_result =
fun _env ->
Ok v
let error (s:string) : 'a ea_result =
fun _env ->
Error s
let (>>=) (c:'a ea_result) (f: 'a -> 'b ea_result) : 'b ea_result =
fun env ->
match c env with
| Error err -> Error err
| Ok v -> f v env
let (>>+) (c:env ea_result) (d:'a ea_result): 'a ea_result =
fun env ->
match c env with
| Error err -> Error err
| Ok newenv -> d newenv
let run (c:'a ea_result) : 'a result =
c EmptyEnv
let lookup_env : env ea_result =
fun env ->
Ok env
(* Operations on environments *)
let empty_env : unit -> env ea_result =
fun () ->
return EmptyEnv
let extend_env : string -> exp_val -> env ea_result =
fun id v env ->
Ok (ExtendEnv(id,v,env))
let rec apply_env : string -> exp_val ea_result =
fun id env ->
match env with
| EmptyEnv -> Error (id^" not found!")
| ExtendEnv(v,ev,tail) ->
if id=v
then Ok ev
else apply_env id tail
let rec extend_env_list =
fun env ids evs ->
match ids,evs with
| [],[] -> Ok (env)
| id::ids, ev::evs -> Ok (extend_env_list (extend_env env id ev) ids evs)
| _,_ -> failwith "extend_env_list: Number of arguments does not match number of parameters!"
(* operations on expressed values *)
let int_of_numVal : exp_val -> int ea_result = function
| NumVal n -> return n
| _ -> error "Expected a number!"
let bool_of_boolVal : exp_val -> bool ea_result = function
| BoolVal b -> return b
| _ -> error "Expected a boolean!"
let list_of_listVal = function
| ListVal l -> return l
| _ -> error "Expected a list!"
let tree_of_treeVal = function
| TreeVal t -> return t
| _ -> error "Expected a tree!"
let is_listVal = function
| ListVal(_) -> return true
| _ -> return false
let rec string_of_list_of_strings = function
| [] -> ""
| [id] -> id
| id::ids -> id ^ "," ^ string_of_list_of_strings ids
let string_of_expval = function
| NumVal n -> "NumVal " ^ string_of_int n
| BoolVal b -> "BoolVal " ^ string_of_bool b
| UnitVal -> "UnitVal"
| _ -> failwith "string_of_expval: undefined"
let rec string_of_env' = function
| EmptyEnv -> ""
| ExtendEnv(id,v,env) -> string_of_env' env^" ("^id^","^string_of_expval v^")\n"
let string_of_env : string ea_result =
fun env ->
Ok ("Environment:\n"^ string_of_env' env)
let obtain_head l =
match l with
| [] -> failwith "Empty list!"
| h::t -> h
let obtain_tail l =
match l with
| [] -> failwith "Empty list!"
| h::t -> t