- | Variable c ->
- (* we don't handle cases where g doesn't bind c to any value *)
- List.assoc c g
- | Let (c, t1, t2) ->
- (* evaluate t2 under a new assignment where c has been bound to
+ | Variable var ->
+ (* we don't handle cases where g doesn't bind var to any value *)
+ List.assoc var g
+ | Let (var_to_bind, t1, t2) ->
+ (* evaluate t2 under a new assignment where var_to_bind has been bound to
- | Lambda(c, t1) -> Closure (c, t1, g)
+ | Lambda(arg_var, t1) -> Closure (arg_var, t1, g)
(* we don't handle cases where t1 doesn't evaluate to a function value *)
let Closure (arg_var, body, savedg) = eval t1 g
(* we don't handle cases where t1 doesn't evaluate to a function value *)
let Closure (arg_var, body, savedg) = eval t1 g
- in let rec new_closure = Closure (arg_var, body, (c, new_closure) :: savedg)
- in let g' = (c, new_closure) :: g
+ in let rec new_closure = Closure (arg_var, body, (var_to_bind, new_closure) :: savedg)
+ in let g' = (var_to_bind, new_closure) :: g
in eval t2 g';;
However, this is a somewhat exotic ability in a programming language, so it would be good to work out how to interpret `Letrec(...)` forms without relying on it.
in eval t2 g';;
However, this is a somewhat exotic ability in a programming language, so it would be good to work out how to interpret `Letrec(...)` forms without relying on it.
If we implemented assignments as functions rather than as lists of pairs, the corresponding move would be less exotic. In that case, our `Let(...)` and `Letrec(...)` clauses would look something like this:
If we implemented assignments as functions rather than as lists of pairs, the corresponding move would be less exotic. In that case, our `Let(...)` and `Letrec(...)` clauses would look something like this:
- in let rec savedg' = fun var -> if var = c then Closure (arg_var, body, savedg') else savedg var
- in let g' = fun var -> if var = c then Closure (arg_var, body, savedg') else g var
+ in let rec savedg' = fun var -> if var = var_to_bind Closure (arg_var, body, savedg') else savedg var
+ in let g' = fun var -> if var = var_to_bind then Closure (arg_var, body, savedg') else g var
in eval t2 g';;
and this is just a run-of-the-mill use of recursive functions. However, for this exercise we'll continue using lists of pairs, and work out how to interpret `Letrec(...)` forms using them.
in eval t2 g';;
and this is just a run-of-the-mill use of recursive functions. However, for this exercise we'll continue using lists of pairs, and work out how to interpret `Letrec(...)` forms using them.
| Nonrecursive value -> value
| Recursive_Closure (self_var, arg_var, body, savedg) as rec_closure ->
(* we update savedg to bind self_var to rec_closure here *)
let savedg' = (self_var, rec_closure) :: savedg
in Closure (arg_var, body, savedg')
)
| Nonrecursive value -> value
| Recursive_Closure (self_var, arg_var, body, savedg) as rec_closure ->
(* we update savedg to bind self_var to rec_closure here *)
let savedg' = (self_var, rec_closure) :: savedg
in Closure (arg_var, body, savedg')
)
the result of evaluating t1 under the current assignment *)
let value1 = eval t1 g
(* we have to wrap value1 in Nonrecursive *)
the result of evaluating t1 under the current assignment *)
let value1 = eval t1 g
(* we have to wrap value1 in Nonrecursive *)
- | Lambda(c, t1) -> Closure (c, t1, g)
+ | Lambda(arg_var, t1) -> Closure (arg_var, t1, g)
(* evaluate body under savedg, except with arg_var bound to Nonrecursive value2 *)
in let savedg' = (arg_var, Nonrecursive value2) :: savedg
in eval body savedg'
(* evaluate body under savedg, except with arg_var bound to Nonrecursive value2 *)
in let savedg' = (arg_var, Nonrecursive value2) :: savedg
in eval body savedg'
(* we don't handle cases where t1 doesn't evaluate to a function value *)
let Closure (arg_var, body, savedg) = eval t1 g
(* we don't handle cases where t1 doesn't evaluate to a function value *)
let Closure (arg_var, body, savedg) = eval t1 g
- (* evaluate t2 under a new assignment where c has been recursively bound to that function value *)
- in let g' = (c, Recursive_Closure(c, arg_var, body, savedg)) :: g
+ (* evaluate t2 under a new assignment where var_to_bind has been recursively bound to that function value *)
+ in let g' = (var_to_bind, Recursive_Closure(var_to_bind, arg_var, body, savedg)) :: g