Ken Wakita (https://wakita.github.io/fp2018/)
Nov 5, 2018
(* closure.ml *)
let rec g env known = function
| ...
| KNormal.App(x, ys) when S.mem x known -> AppDir(Id.L(x), ys)
| KNormal.App(f, xs) -> AppCls(f, xs)
| ...
Cs(x y1…yn)={apply_closure(x,y1,…,yn)x∉sapply_direct(Lx,y1,…,yn)x∈s
| KNormal.LetRec({ KNormal.name = (x, t); KNormal.args = yts; KNormal.body = e1 }, e2) ->
(* Attempt closure conversion, assuming x containing no free variables: Cases 1, 2 *)
(* if e1' contains free variable (* our assumption is not met *) then
(* Retry conversion: Case 3 *)
(* Generate toplevel function definition *)
(* Case 1, 3: Create closure *)
e2'
known
and e1'
for Case 1, 2(* Attempt closure conversion, assuming x containing no free variables: Case 1 or 2 *)
let toplevel_backup = !toplevel in
let env' = M.add x t env in
let known' = S.add x known in
let e1' = g (M.add_list yts env') known' e1 in
let zs = S.diff (fv e1') (S.of_list (List.map fst yts)) in
let known', e1' =
if S.is_empty zs then known', e1' (* confirm that variables are closed in e1' *)
else Retry conversion because the assertion was not met (* Case 3 *)
...
(* Generate toplevel function definition *)
(* Create closure if needed: case 1 or 3 *)
e2'
known
and e1'
for Case 3let known', e1' =
if S.is_empty zs then known', e1' (* confirm that variables are closed in e1' *)
else (* Retry conversion because the assertion was not met *)
(toplevel := toplevel_backup; (* reset side effects of conversions for subexpressions *)
let e1' = g (M.add_list yts env') known e1 in
known, e1') in
| KNormal.LetRec({ KNormal.name = (x, t); KNormal.args = yts; KNormal.body = e1 }, e2) ->
(* Attempt closure conversion, assuming x containing no free variables: Case 1 *)
if e1' contains free variable (* our assumption is not met *) then
(* Retry conversion: Case 2 or 3 *)
(* Generate toplevel function definition *)
(* Case 1, 3: Create closure *)
e2'
(* a list of free variables = x, y1, ..., yn *)
let zs = S.elements (S.diff (fv e1') (S.add x (S.of_list (List.map fst yts)))) in
(* free variables with type annotations *)
let zts = List.map (fun z -> (z, M.find z env')) zs in
toplevel := { name = (Id.L(x), t); args = yts; formal_fv = zts; body = e1' } :: !toplevel;
MakeCls
and e2'
(1/2) | KNormal.LetRec({ KNormal.name = (x, t); KNormal.args = yts; KNormal.body = e1 }, e2) ->
(* Attempt closure conversion, assuming x containing no free variables: Case 1 *)
if e1' contains free variable (* our assumption is not met *) then
(* Retry conversion: Case 2 or 3 *)
(* Generate toplevel function definition *)
(* Case 1, 3: Create closure *)
e2'
MakeCls
and e2'
(2/2)let e2' = g env' known' e2 in
if S.mem x (fv e2') then (* does x occur in e2' ? *)
MakeCls((x, t), { entry = Id.L(x); actual_fv = zs }, e2')
else e2'