git @ Cat's Eye Technologies Lanthorn / 47b7adf
Properly handle `letrec` of functions with more than one argument. Chris Pressey 6 months ago
3 changed file(s) with 51 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
9999 hygiene.
100100 * The transformation should retain the names of the original
101101 arguments of the functions.
102 * There needs to be a test confirming that it can handle multiple
103 arguments in the original functions.
104102
105103 Appendix A
106104 ----------
287285 in
288286 if oddp(target) then factopen(factopen, target) else 0
289287 ===> 5040
288
289 `letrec` works on functions that have more than one argument.
290
291 letrec
292 oddsump = fun(x,y,z) -> if eq(add(x, add(y, z)), add(y, z)) then false else evensump(sub(x, 1), y, z)
293 evensump = fun(x,y,z) -> if eq(add(x, add(y, z)), add(y, z)) then true else oddsump(sub(x, 1), y, z)
294 in
295 evensump(5,3,1)
296 ===> false
297
298 letrec
299 oddsump = fun(x,y,z) -> if eq(add(x, add(y, z)), add(y, z)) then false else evensump(sub(x, 1), y, z)
300 evensump = fun(x,y,z) -> if eq(add(x, add(y, z)), add(y, z)) then true else oddsump(sub(x, 1), y, z)
301 in
302 evensump(6,3,1)
303 ===> true
304
305 -> Tests for functionality "Desugar Lanthorn Program"
306
307 Let's see how that gets desugared. The innermost `let`s bind the plain
308 names to functions with the same arity as the original functions.
309
310 letrec
311 oddsump = fun(x,y,z) -> if eq(add(x, add(y, z)), add(y, z)) then false else evensump(sub(x, 1), y, z)
312 evensump = fun(x,y,z) -> if eq(add(x, add(y, z)), add(y, z)) then true else oddsump(sub(x, 1), y, z)
313 in
314 evensump(5,3,1)
315 => let
316 => oddsump0 = fun(x, y, z, oddsump1, evensump1) -> let
317 => oddsump = fun(x1, y1, z1) -> oddsump1(x1, y1, z1, oddsump1, evensump1)
318 => evensump = fun(x1, y1, z1) -> evensump1(x1, y1, z1, oddsump1, evensump1)
319 => in
320 => if eq(add(x, add(y, z)), add(y, z)) then false else evensump(sub(x, 1), y, z)
321 => evensump0 = fun(x, y, z, oddsump1, evensump1) -> let
322 => oddsump = fun(x1, y1, z1) -> oddsump1(x1, y1, z1, oddsump1, evensump1)
323 => evensump = fun(x1, y1, z1) -> evensump1(x1, y1, z1, oddsump1, evensump1)
324 => in
325 => if eq(add(x, add(y, z)), add(y, z)) then true else oddsump(sub(x, 1), y, z)
326 => oddsump = fun(x, y, z) -> oddsump0(x, y, z, oddsump0, evensump0)
327 => evensump = fun(x, y, z) -> evensump0(x, y, z, oddsump0, evensump0)
328 => in
329 => evensump(5, 3, 1)
2121 [
2222 ("true", Boolean True),
2323 ("false", Boolean False),
24 ("add", Function (\[Number a, Number b] -> Number (a + b))),
2425 ("sub", Function (\[Number a, Number b] -> Number (a - b))),
2526 ("mul", Function (\[Number a, Number b] -> Number (a * b))),
2627 ("eq", Function (\[a, b] -> Boolean (a == b)))
3333 let
3434 name' = wrapperNameOuter name
3535 formals' = formals ++ (map (wrapperNameInner) injecteds)
36 body' = (LetStar (createLocalBindings injecteds injecteds) body)
36 body' = (LetStar (createLocalBindings injecteds injecteds formals) body)
3737 expr' = (Fun formals' body')
3838 binding = (name', expr')
3939 in
4141 createEnrichedBindings (binding:rest) injecteds =
4242 (binding:createEnrichedBindings rest injecteds)
4343
44 createLocalBindings [] _ = []
45 createLocalBindings (injected:injecteds) allInjecteds =
44 createLocalBindings [] _ _ = []
45 createLocalBindings (injected:injecteds) allInjecteds formals =
4646 let
47 -- FIXME use the real formals of each injected identifier! also, allow shadowing!
48 actuals = map (ValueOf) (["x1"] ++ (map (wrapperNameInner) allInjecteds))
49 binding = (injected, Fun ["x1"] (Apply (wrapperNameInner injected) actuals))
47 formals' = map (wrapperNameInner) formals
48 actuals = map (ValueOf) (formals' ++ (map (wrapperNameInner) allInjecteds))
49 binding = (injected, Fun formals' (Apply (wrapperNameInner injected) actuals))
50 rest = createLocalBindings injecteds allInjecteds formals
5051 in
51 (binding:createLocalBindings injecteds allInjecteds)
52 (binding:rest)
5253
5354 createWrapperBindings [] injecteds = []
5455 createWrapperBindings ((name, (Fun formals body)):rest) injecteds =