Arc Forumnew | comments | leaders | submitlogin
1 point by rntz 5662 days ago | link | parent

Here's a working version of 'once-only. It avoids nested quasiquotation, because I was unfamiliar with how it worked at the time I wrote it.

    ;; encapsulates idiom: (w/uniq o `(let ,o ,obj ...))
    (mac once-only (names exp)
      (withs (names (if atom.names (list names) names)
              names-temps (map [list (uniq) _] names))
        `(with ,(apply join names-temps)
           (w/uniq ,names
             (list 'with (list ,@(mappend (fn ((name tmp)) (list tmp name))
                                   names-temps))
               ,exp)))))


1 point by fallintothis 5661 days ago | link

Ah, I hadn't thought to mangle around with explicit lists; probably because I find it uglier than quasiquotation.

Siebel's version then becomes:

  (mac once-only (names . body)
    (let gensyms (map1 [uniq] names)
      `(w/uniq ,gensyms
         (list 'with (list ,@(mappend list gensyms names))
           (with ,(mappend list names gensyms)
             ,@body)))))
Could be worse. And it's usable, e.g.:

   (mac for (v init max . body)
     (once-only (init max)
       `(with (,v nil ,max (+ ,max 1))
          (loop (assign ,v ,init) (< ,v ,max) (assign ,v (+ ,v 1))
            ,@body))))
  *** redefining for
  #3(tagged mac #<procedure: for>)
  arc> (for x 1 5 (prn x))
  1
  2
  3
  4
  5
  nil
  arc> (for init 1 5 (prn init))
  1
  2
  3
  4
  5
  nil
  arc> (let max 2 (for init 1 5 (when (> init max) (prn init))))
  3
  4
  5
  nil
  arc> (for x 1 5 (prn init))
  Error: "reference to undefined identifier: _init"
Thanks for the help!

-----

3 points by fallintothis 5661 days ago | link

Not that anyone cares about beating this dead horse, but after coming back to the code, I instantly realized how to mitigate the ,,@(...) snafu:

  (mac once-only (names . body)
    (let gensyms (map1 [uniq] names)
      `(w/uniq ,gensyms
        `(with ,(list ,@(mappend list gensyms names))
          ,(with ,(mappend list names gensyms)
            ,@body)))))
Seems obvious in retrospect. (Also, I've been spelling Peter Seibel's name wrong in this thread; oops.)

-----