On 08/24/2012 06:23 PM, Michael Wilber wrote:
This is interesting, but I don't understand how moving cons around keeps
it from allocating? In particular, why are the cons calls "evaluated at
expansion time" when we may not even know the length of the list during
macro expansion time?

If I write (inline-sort a b c), then the macro certainly knows the length of the syntax list #'(a b c) when it expands.

The difference between evaluating conses at expansion time and evaluating them at runtime is that, at expansion time, they contain the *syntax* that gets evaluated at runtime. At runtime, they contain the runtime values. We might use cons to build a syntax list like this:

  (cons #'values (cons #'a (cons #'b (cons #'c empty))))

which evaluates at expansion time to something more or less equivalent to #'(values a b c). At runtime, #'values is evaluated, then #'a, then #'b, then #'c, and finally the value of #'values is applied to the others.

Near the top of the post, it says the code "would be slow because cons
allocates." But how does this:

(define (list-add1/acc vs [acc (list)])
   (match vs
     [(list)  (reverse acc)]
     [(list v vs ...)
      (list-add1/acc vs (cons (add1 v) acc))]))

...make the code *faster*? The only thing we've done is move the
recursive step into tail position; we haven't changed the fact that we
still need to apply cons to the arguments. This also comes at the cost
of introducing an expensive (reverse) step.

That's a good question. In general, the fact that the recursive call is tail-call-optimized more than makes up for the list reversal, making accumulator-passing style faster.

But that's not what I was after at all. (Probably a communication failure on my part.) In that section, I was concentrating only on moving the `cons' inward. I wanted to take the small step from something like this:

  (if (< a b)
      (cons a (if ... (cons b ...) (cons c ...)))
      (cons b (if ... (cons a ...) (cons c ...))))

to something like this:

  (if (< a b)
      (if ... (cons a (cons b ...)) (cons a (cons c ...)))
      (if ... (cons b (cons a ...)) (cons b (cons c ...))))

to group all those conses together before moving parts of the code to the expansion phase. With them grouped, it's possible to transform them into a `values' expression at expansion time.

APS is a typical way to move conses inward, but it doesn't work on the merge sort. CPS is a more general way to move conses from the outside of an expression to the inside.

Does this only work on literal values?

Heck no. :) It'd be useless to me if it did.

I've been considering the best ways to make it work on literal values, though. It's not unusual to want to sort something like (list a b 2 c).

Neil ⊥

____________________
 Racket Users list:
 http://lists.racket-lang.org/users

Reply via email to