git.haldean.org ubik / ed2d20d
fix line breaks in recursion.txt Haldean Brown 3 years ago
1 changed file(s) with 31 addition(s) and 29 deletion(s). Raw diff Collapse all Expand all
4747 ! t 1
4848 }
4949
50 In this example, t needs access to its own value from within its definition.
51 However, since t is a local binding, it's never actually assigned to a name
52 that persists past its own scope. To handle this, we transform t to take itself
53 as a parameter; callers then call t by passing it itself. The resulting
54 function then looks like:
50 In this example, t needs access to its own value from within its
51 definition. However, since t is a local binding, it's never actually
52 assigned to a name that persists past its own scope. To handle this, we
53 transform t to take itself as a parameter; callers then call t by
54 passing it itself. The resulting function then looks like:
5555
5656 : t = \$t x -> ? {
5757 . eq x 0 => "ok\n"
5858 . => $t $t 0
5959 }
6060
61 This poses a problem for the callers of this function, though; now all callers
62 have to know that t needs to be passed itself as its first argument, so the
63 immediate value of the block would be transformed to:
61 This poses a problem for the callers of this function, though; now all
62 callers have to know that t needs to be passed itself as its first
63 argument, so the immediate value of the block would be transformed to:
6464
6565 ! t t 1
6666
67 But this is clunky; we don't want to have to transform every call site that
68 references t. Instead, we transform t to a partially-applied function, with
69 itself already applied (for brevity, B is used to represent the body of the
70 function t as given in the previous listing):
67 But this is clunky; we don't want to have to transform every call site
68 that references t. Instead, we transform t to a partially-applied
69 function, with itself already applied (for brevity, B is used to
70 represent the body of the function t as given in the previous listing):
7171
7272 : t = (\$t x -> B) (\$t x -> B)
7373
74 Note that this can be very succinctly represented in Ubik bytecode, without
75 requiring a double-definition of the function, as the function must be its own
76 value:
74 Note that this can be very succinctly represented in Ubik bytecode,
75 without requiring a double-definition of the function, as the function
76 must be its own value:
7777
7878 000 VALUE &B
7979 001 APPLY 000 000
8080
81 This seems nice in practice, but there's one more sticky bit: the original
82 closure transformation. Let's take a slightly more complicated example:
81 This seems nice in practice, but there's one more sticky bit: the
82 original closure transformation. Let's take a slightly more complicated
83 example:
8384
8485 : top = \x -> {
8586 : inner = \y -> inner (+ x y)
8687 ! inner
8788 }
8889
89 Never mind that this is infinitely recursive: it's a nice simple example for
90 our syntactic transformations. The closure transformation takes inner from that
91 given in the previous listing to this:
90 Never mind that this is infinitely recursive: it's a nice simple example
91 for our syntactic transformations. The closure transformation takes
92 inner from that given in the previous listing to this:
9293
9394 : inner = (\x y -> inner (+ x y)) x
9495
99100 (\inner x y -> inner inner (+ x y))
100101 x
101102
102 This looks okay, but doesn't properly work, because the reference to inner in
103 the body of the function doesn't pass any of the closed-over parameters. What
104 we want is something more like:
103 This looks okay, but doesn't properly work, because the reference to
104 inner in the body of the function doesn't pass any of the closed-over
105 parameters. What we want is something more like:
105106
106107 : top = \x -> {
107108 : inner_ = \x inner y -> inner (+ x y)
109110 : inner_with_inner_ = inner_with_x_ inner_with_x_
110111 }
111112
112 But that doesn't work either. Hm. Instead, we introduce a secret atom type,
113 SELFREF, which is a reference to the innermost enclosing function. So we end up
114 rewriting inner to be:
113 But that doesn't work either. Instead, we introduce a secret atom type,
114 SELFREF, which is a reference to the innermost enclosing function. So
115 we end up rewriting inner to be:
115116
116117 : inner = (\x y -> {
117118 : inner = SELFREF x
118119 ! inner (+ x y)
119120 }) x
120121
121 Now the "inner" on the inside doesn't actually reference a named binding on the
122 outside. When this is compiled down to a graph, SELFREF will be transformed
123 into a VALUE node that points at the value currently being compiled.
122 Now the "inner" on the inside doesn't actually reference a named binding
123 on the outside. When this is compiled down to a graph, SELFREF will be
124 transformed into a VALUE node that points at the value currently being
125 compiled.
124126
125127 With more-heavily-nested recursion, this ends up transforming:
126128