git @ Cat's Eye Technologies Lanthorn / 6b0d4d6
The transformation makes more effort at hygiene, with name-mangling. Chris Pressey 6 months ago
2 changed file(s) with 51 addition(s) and 50 deletion(s). Raw diff Collapse all Expand all
4242 ...and turn it into this.
4343
4444 let
45 odd0 = fun(x, odd1, even1) ->
45 odd0 = fun(x, odd$1, even$1) ->
4646 let
4747 odd = fun(x) -> odd1(x, odd1, even1)
4848 even = fun(x) -> even1(x, odd1, even1)
6161
6262 Our evaluator implements this transformation in the
6363 [Language.Lanthorn.LetRec](src/Language/Lanthorn/LetRec.hs) module.
64 Here is what it produces:
64 Here is what it produces. Note there is a bit of name-mangling
65 added, compared to the hand-written expansion above.
6566
6667 letrec
6768 odd = fun(x) -> if eq(x, 0) then false else even(sub(x, 1))
6970 in
7071 even(6)
7172 => let
72 => odd0 = fun(x, odd1, even1) -> let
73 => odd = fun(x1) -> odd1(x1, odd1, even1)
74 => even = fun(x1) -> even1(x1, odd1, even1)
73 => odd$0 = fun(x, odd$1, even$1) -> let
74 => odd = fun(x$1) -> odd$1(x$1, odd$1, even$1)
75 => even = fun(x$1) -> even$1(x$1, odd$1, even$1)
7576 => in
7677 => if eq(x, 0) then false else even(sub(x, 1))
77 => even0 = fun(x, odd1, even1) -> let
78 => odd = fun(x1) -> odd1(x1, odd1, even1)
79 => even = fun(x1) -> even1(x1, odd1, even1)
78 => even$0 = fun(x, odd$1, even$1) -> let
79 => odd = fun(x$1) -> odd$1(x$1, odd$1, even$1)
80 => even = fun(x$1) -> even$1(x$1, odd$1, even$1)
8081 => in
8182 => if eq(x, 0) then true else odd(sub(x, 1))
82 => odd = fun(x) -> odd0(x, odd0, even0)
83 => even = fun(x) -> even0(x, odd0, even0)
83 => odd = fun(x) -> odd$0(x, odd$0, even$0)
84 => even = fun(x) -> even$0(x, odd$0, even$0)
8485 => in
8586 => even(6)
8687
9192 it makes. It also sets up some bindings outside of these functions
9293 to that the body of the `letrec` sees functions with the original
9394 parameters they had, hiding all these extra parameters.
94
95 TODO
96 ----
97
98 * The transformation should make more effort at name mangling
99 hygiene.
10095
10196 Appendix A
10297 ----------
348343 in
349344 evensump(5,3,1)
350345 => let
351 => oddsump0 = fun(x, y, z, oddsump1, evensump1) -> let
352 => oddsump = fun(x1, y1, z1) -> oddsump1(x1, y1, z1, oddsump1, evensump1)
353 => evensump = fun(x1, y1, z1) -> evensump1(x1, y1, z1, oddsump1, evensump1)
346 => oddsump$0 = fun(x, y, z, oddsump$1, evensump$1) -> let
347 => oddsump = fun(x$1, y$1, z$1) -> oddsump$1(x$1, y$1, z$1, oddsump$1, evensump$1)
348 => evensump = fun(x$1, y$1, z$1) -> evensump$1(x$1, y$1, z$1, oddsump$1, evensump$1)
354349 => in
355350 => if eq(add(x, add(y, z)), add(y, z)) then false else evensump(sub(x, 1), y, z)
356 => evensump0 = fun(x, y, z, oddsump1, evensump1) -> let
357 => oddsump = fun(x1, y1, z1) -> oddsump1(x1, y1, z1, oddsump1, evensump1)
358 => evensump = fun(x1, y1, z1) -> evensump1(x1, y1, z1, oddsump1, evensump1)
351 => evensump$0 = fun(x, y, z, oddsump$1, evensump$1) -> let
352 => oddsump = fun(x$1, y$1, z$1) -> oddsump$1(x$1, y$1, z$1, oddsump$1, evensump$1)
353 => evensump = fun(x$1, y$1, z$1) -> evensump$1(x$1, y$1, z$1, oddsump$1, evensump$1)
359354 => in
360355 => if eq(add(x, add(y, z)), add(y, z)) then true else oddsump(sub(x, 1), y, z)
361 => oddsump = fun(x, y, z) -> oddsump0(x, y, z, oddsump0, evensump0)
362 => evensump = fun(x, y, z) -> evensump0(x, y, z, oddsump0, evensump0)
356 => oddsump = fun(x, y, z) -> oddsump$0(x, y, z, oddsump$0, evensump$0)
357 => evensump = fun(x, y, z) -> evensump$0(x, y, z, oddsump$0, evensump$0)
363358 => in
364359 => evensump(5, 3, 1)
365360
366361 The transformation mangles names that it generates so that they never
367 shadow names that appear in the user's program.
362 shadow names that appear in the user's program. (Names containing `$` may
363 not appear in a user-supplied program.)
368364
369365 let
370366 odd0 = fun(a, b, c) -> a
378374 => odd0 = fun(a, b, c) -> a
379375 => in
380376 => let
381 => odd0 = fun(x, odd1, even1) -> let
382 => odd = fun(x1) -> odd1(x1, odd1, even1)
383 => even = fun(x1) -> even1(x1, odd1, even1)
377 => odd$0 = fun(x, odd$1, even$1) -> let
378 => odd = fun(x$1) -> odd$1(x$1, odd$1, even$1)
379 => even = fun(x$1) -> even$1(x$1, odd$1, even$1)
384380 => in
385381 => if eq(x, 0) then false else even(sub(x, 1))
386 => even0 = fun(x, odd1, even1) -> let
387 => odd = fun(x1) -> odd1(x1, odd1, even1)
388 => even = fun(x1) -> even1(x1, odd1, even1)
382 => even$0 = fun(x, odd$1, even$1) -> let
383 => odd = fun(x$1) -> odd$1(x$1, odd$1, even$1)
384 => even = fun(x$1) -> even$1(x$1, odd$1, even$1)
389385 => in
390386 => if eq(x, 0) then true else odd(sub(x, 1))
391 => odd = fun(x) -> odd0(x, odd0, even0)
392 => even = fun(x) -> even0(x, odd0, even0)
387 => odd = fun(x) -> odd$0(x, odd$0, even$0)
388 => even = fun(x) -> even$0(x, odd$0, even$0)
393389 => in
394390 => even(6)
395391
418414 in
419415 even(6)
420416 => let
421 => odd0 = fun(x, odd1, odd01, even1) -> let
422 => odd = fun(x1) -> odd1(x1, odd1, odd01, even1)
423 => odd0 = fun(a1, b1, c1) -> odd01(a1, b1, c1, odd1, odd01, even1)
424 => even = fun(x1) -> even1(x1, odd1, odd01, even1)
417 => odd$0 = fun(x, odd$1, odd0$1, even$1) -> let
418 => odd = fun(x$1) -> odd$1(x$1, odd$1, odd0$1, even$1)
419 => odd0 = fun(a$1, b$1, c$1) -> odd0$1(a$1, b$1, c$1, odd$1, odd0$1, even$1)
420 => even = fun(x$1) -> even$1(x$1, odd$1, odd0$1, even$1)
425421 => in
426422 => if eq(x, 0) then false else even(sub(x, 1))
427 => odd00 = fun(a, b, c, odd1, odd01, even1) -> let
428 => odd = fun(x1) -> odd1(x1, odd1, odd01, even1)
429 => odd0 = fun(a1, b1, c1) -> odd01(a1, b1, c1, odd1, odd01, even1)
430 => even = fun(x1) -> even1(x1, odd1, odd01, even1)
423 => odd0$0 = fun(a, b, c, odd$1, odd0$1, even$1) -> let
424 => odd = fun(x$1) -> odd$1(x$1, odd$1, odd0$1, even$1)
425 => odd0 = fun(a$1, b$1, c$1) -> odd0$1(a$1, b$1, c$1, odd$1, odd0$1, even$1)
426 => even = fun(x$1) -> even$1(x$1, odd$1, odd0$1, even$1)
431427 => in
432428 => a
433 => even0 = fun(x, odd1, odd01, even1) -> let
434 => odd = fun(x1) -> odd1(x1, odd1, odd01, even1)
435 => odd0 = fun(a1, b1, c1) -> odd01(a1, b1, c1, odd1, odd01, even1)
436 => even = fun(x1) -> even1(x1, odd1, odd01, even1)
429 => even$0 = fun(x, odd$1, odd0$1, even$1) -> let
430 => odd = fun(x$1) -> odd$1(x$1, odd$1, odd0$1, even$1)
431 => odd0 = fun(a$1, b$1, c$1) -> odd0$1(a$1, b$1, c$1, odd$1, odd0$1, even$1)
432 => even = fun(x$1) -> even$1(x$1, odd$1, odd0$1, even$1)
437433 => in
438434 => if eq(x, 0) then true else odd(sub(x, 1))
439 => odd = fun(x) -> odd0(x, odd0, odd00, even0)
440 => odd0 = fun(a, b, c) -> odd00(a, b, c, odd0, odd00, even0)
441 => even = fun(x) -> even0(x, odd0, odd00, even0)
435 => odd = fun(x) -> odd$0(x, odd$0, odd0$0, even$0)
436 => odd0 = fun(a, b, c) -> odd0$0(a, b, c, odd$0, odd0$0, even$0)
437 => even = fun(x) -> even$0(x, odd$0, odd0$0, even$0)
442438 => in
443439 => even(6)
444440
453449 in
454450 even(6)
455451 ===> true
452
453 Note that there is probably a case where a `letrec` nested another `letrec`, and
454 which shadows variables of the enclosing `letrec`, produces a less readable
455 error message about shadowing, because it mentions the mangled names; but
456 I can live with that for now.
3232 in
3333 LetStar (enrichedBindings ++ wrapperBindings) body
3434
35 wrapperNameOuter name = name ++ "0" -- TODO: more hygenic!
36 wrapperNameInner name = name ++ "1"
35 wrapperNameOuter name = name ++ "$0"
36 wrapperNameInner name = name ++ "$1"
3737
3838 createEnrichedBindings [] injecteds = []
3939 createEnrichedBindings (binding@(name, (Fun formals body)):rest) injecteds =