Arc Forumnew | comments | leaders | submitlogin
4 points by fallintothis 5224 days ago | link | parent

That version of macex-all is a bit primitive.

  arc> (macex-all '(fn (do re mi) (+ do re mi)))
  (fn ((fn () re mi)) (+ do re mi))
  arc> (macex-all ''(do not expand this -- it is quoted))
  (quote ((fn () not expand this -- it is quoted)))
If you want a more robust macex-all, you can gank my implementation from http://arclanguage.org/item?id=11806 (rewritten slightly):

  (def imap (f xs)
    (when xs
      (if (acons xs)
          (cons (f (car xs)) (imap f (cdr xs)))
          (f xs))))

  (def macex-all (expr)
    (zap macex expr)
    (check expr
           atom
           (case (car expr)
             quasiquote (list 'quasiquote
                              ((afn (level x)
                                 (if (is level 0)
                                      (macex-all x)
                                     (caris x 'quasiquote)
                                      (list 'quasiquote (self (+ level 1) cadr.x))
                                     (in acons&car.x 'unquote 'unquote-splicing)
                                      (list car.x (self (- level 1) cadr.x))
                                      (check x atom (imap [self level _] x))))
                               1 (cadr expr)))
             fn         `(fn ,(cadr expr) ,@(imap macex-all (cddr expr)))
             quote      expr
                        (imap macex-all expr))))
This also won't break on dotted lists, like

  arc> (macex-all '`(a . b))
  Error: "Can't take car of b"
But if you don't care about that, you can replace all the uses of imap with map1 or map.

Also, a couple nitpicks about dec.

  (macex-all body)
breaks, because body is a list, so if its car is a macro, macex-all thinks it's a macro call.

  arc> (ppr:macex1 '(dec foo bar
                      mac baz quux quack))
  (do (fn ()
        (sref sig 'quux 'baz)
        ((fn ()
           (if (bound 'baz)
               ((fn ()
                  (disp "*** redefining " (stderr))
                  (disp 'baz (stderr))
                  (disp #\newline (stderr)))))
           (assign baz
                   (annotate 'mac (fn quux quack)))))))t
Notice too that consing do to the front breaks in this case. So, you should use

  (map1 macex-all body)
You won't need to care about dotted lists, since body will be proper (rest parameters in Arc always are).

Finally, the pattern

  (let result x
    ... stuff not involving x or result ...
    result)
is exactly what do1 is for. Altogether, that's

  (mac dec (obj type . body)
    (let oldtype (declare-obj-class* obj)
      (= (declare-obj-class* obj) type)
      (do1 (cons 'do (map1 macex-all body))
           (= (declare-obj-class* obj) oldtype))))