1 (*********************************************************************
3 **********************************************************************)
5 let (|>) (p
: 'a
) (f
: 'a
-> 'b
) = f p
;;
11 let is_none x
= not
(is_some x
);;
13 let get_some = function
15 | None
-> raise Not_found
17 exception Scheme_cast_error
;;
19 exception Scheme_eval_error
of string;;
20 let eval_error s
= raise
(Scheme_eval_error s
);;
22 type symbol
= string ;;
25 A scheme object is anything that can be considered a value in Scheme. Notice that:
27 - Any symbolic expression can be an object (through the use of quote).
28 - Some objects have a literal representation in the program (can be read), but others don't: Closures and Continuations are created through evaluation of some other expressions.
38 | Quotation
of scheme_object
39 | ProperList
of scheme_object list
40 | ImproperList
of (scheme_object list
) * scheme_object
41 | Closure
of scheme_object
* scheme_environment
* (symbol list
)
42 | Continuation
of scheme_environment
* (scheme_object
-> scheme_object
)
44 environment_frame
= (string, scheme_object
) Hashtbl.t
46 scheme_environment
= environment_frame list
49 let get_int = function
51 | _
-> raise Scheme_cast_error
;;
53 (**********************************************************************
55 **********************************************************************)
56 let env_from_alist alist
=
57 let h = Hashtbl.create
1 in
58 List.iter
(fun (k
, v
) -> Hashtbl.add
h k v
) alist
;
62 let push_env_frame env formals actuals
=
63 let h = Hashtbl.create
(List.length formals
) in
65 (function (name
, obj
) -> Hashtbl.add
h name obj
)
66 (List.combine formals actuals
);
71 Hashtbl.find
(List.find
(fun x
-> Hashtbl.mem x k
) env
) k
;;
73 let current_env_frame = function
78 (**********************************************************************
80 **********************************************************************)
81 let make_arith_op_builtin_func (base
:int) (f
:int -> int -> int) =
82 List.fold_left
(fun x
-> fun y
-> Int
(f
(get_int x
) (get_int y
))) (Int base
) ;;
84 let builtin_begin params
= List.hd
(List.rev params
)
86 let builtin_option = function
87 "+" -> Some
(make_arith_op_builtin_func 0 ( + ))
88 | "-" -> Some
(make_arith_op_builtin_func 0 ( - ))
89 | "*" -> Some
(make_arith_op_builtin_func 1 ( * ))
90 | "/" -> Some
(make_arith_op_builtin_func 1 ( / ))
91 | "begin" -> Some
builtin_begin
95 (**********************************************************************
97 **********************************************************************)
98 let rec eval (e
:scheme_environment
) (exp
:scheme_object
) =
99 let exp_eval = (eval e
) in
101 | ProperList
(Symbol
"define"::Symbol var
::cdr
) ->
102 let f = current_env_frame e
in
103 Hashtbl.add
f var
(exp_eval (ProperList
((Symbol
"begin")::cdr
)));
105 | ProperList
(Symbol
"lambda"::formals
::body
) ->
106 let proper_body = ProperList
(Symbol
"begin"::body
) in
107 let syms = match formals
with
108 ProperList l
-> (List.map
(function
110 | _
-> eval_error "Invalid formal parameter list") l
)
111 | _
-> eval_error "Bad lambda syntax"
113 Closure
(proper_body, e
, syms)
114 | ProperList
(Symbol
"if"::test
::true_case
::[false_case
]) ->
115 (match (exp_eval test
) with
116 False
-> exp_eval false_case
117 | _
-> exp_eval true_case
)
118 | ProperList
(f::params
) ->
119 let evaluated_params = (List.map
exp_eval params
) in
121 Symbol op
when is_some (builtin_option op
) ->
122 let fbuiltin = op
|> builtin_option |> get_some in
123 (fbuiltin evaluated_params)
124 | Closure
(body
, closure_env
, formals
) ->
125 eval (push_env_frame closure_env formals
evaluated_params) body
126 | _
-> eval_error "Cannot apply non-object" )
129 | whatever
-> whatever
(* Int, String, Quotation, Null *)
132 (**********************************************************************
134 **********************************************************************)
135 let rec eval_cps (e
:scheme_environment
) (exp
:scheme_object
) (return
:scheme_object
-> scheme_object
) =
136 let exp_eval = eval_cps e
in
138 | ProperList
(Symbol
"define"::Symbol var
::[expression
]) ->
139 exp_eval expression
(fun expression_value
->
140 let f = current_env_frame e
in
141 Hashtbl.add
f var expression_value
;
143 | ProperList
(Symbol
"lambda"::formals
::body
) ->
144 let proper_body = ProperList
(Symbol
"begin"::body
) in
145 let syms = match formals
with
146 ProperList l
-> (List.map
(function
148 | _
-> eval_error "Invalid formal parameter list") l
)
149 | _
-> eval_error "Bad lambda syntax"
151 return
(Closure
(proper_body, e
, syms))
152 | ProperList
(Symbol
"call/cc"::[callee
]) ->
153 let continuation = Continuation
(e
, return
) in
154 eval_application e callee
[continuation] return
155 | ProperList
(Symbol
"if"::test
::true_case
::[false_case
]) ->
156 exp_eval test
(function
157 False
-> exp_eval false_case return
158 | _
-> exp_eval true_case return
)
159 | ProperList
(f::params
) ->
160 eval_list_cps e
(ProperList params
)
162 ProperList
evaluated_params ->
163 (eval_application e
f evaluated_params return
)
164 | _
-> invalid_arg
"eval_list_cps did not return a proper list object")
168 return whatever
(* Int, String, Quotation, Null *)
169 and eval_list_cps
(env
:scheme_environment
) (exp
:scheme_object
) (return
: scheme_object
-> scheme_object
) =
171 ProperList
[] as base
-> return base
172 | ProperList
(car
::cdr
) ->
174 (fun (car_result
:scheme_object
) ->
175 (eval_list_cps env
(ProperList cdr
)
177 ProperList
(cdr_result
) -> return
(ProperList
(car_result
::cdr_result
))
178 |_
-> assert false)))
179 | _
-> invalid_arg
"eval_list_cps called with a non-list scheme object"
181 and eval_application e
f evaluated_params return
=
183 Symbol op
when is_some (builtin_option op
) ->
184 let fbuiltin = op
|> builtin_option |> get_some in
185 return
(fbuiltin evaluated_params)
186 | _
-> eval_cps e
f (function
187 | Closure
(body
, closure_env
, formals
) ->
188 eval_cps (push_env_frame closure_env formals
evaluated_params) body return
189 | Continuation
(e
, escape_proc
) ->
190 (escape_proc
(List.hd
evaluated_params))
191 | _
-> eval_error "Trying to apply something that is not a closure")
195 (**********************************************************************)
196 let e = env_from_alist [("a", (Int
1));
202 let print_res = function
203 Int i
-> (Printf.printf
"Res: %d\n" i
); Int i
204 | _
-> assert false ;;
206 let eval0 = eval [e];;
207 let eval1 obj
= eval_cps [e] obj
print_res;;
209 assert ((eval1 (ProperList
[Symbol
"+";Int
2; Symbol
"a"])) = Int
3);;
210 assert ((eval1 (ProperList
[Symbol
"begin"; Int
1; Int
2])) = Int
2);;
212 (***********************************************************************)
215 (eval1 (ProperList
[ Symbol
"if";
216 Quotation
(Symbol
"true-val");
220 ((eval1 (ProperList
[Symbol
"+";Int
2; Symbol
"a"])) = Int
3);;
221 (eval1 (ProperList
[ Symbol
"begin";
222 ProperList
[Symbol
"define"; Symbol
"x"; Int
3];