Using a tree representation enables sharing to avoid a quadratic-sized
compiled form and intermediate quadtraic-time/space representations
for a program like this one, where there are N calls each with an
average of N/2 live variables:
(define vars
(let loop ([i 10000])
(cond
[(zero? i) '()]
[else (cons (gensym) (loop (sub1 i)))])))
(time
(begin
(compile
`(lambda ,vars
,@(map (lambda (v) `(,v)) vars)))
(void)))
Keeping the variables in tree form (since they're already collected
that way) and memoizing reduces on the tree allows sharing to be
constructed and preserved. The tree approach persists even to the
runtime mask for live variables.
original commit: 35942accb14d1226189605548a9e05ca95e3f0b6