Arc Forumnew | comments | leaders | submitlogin
Macros for Anaphora
5 points by fallintothis 3100 days ago | 1 comment
I somehow got interested in anaphora today. I've scribbled some Arc-equivalents to the On Lisp anaphora macros before, but don't think I've ever seen 'em floating around here. So, here are some snippets, for pedagogy's sake.

  (mac anaph (op . args)
    ((afn (args call)
       (if args
           (w/uniq u
             `(withs (,u ,(car args) it ,u)
                ,(self (cdr args)
                       (join call (list u)))))
           call))
     args (list op)))

  (mac anaph1 (op . args)
    `(let it ,(car args) (,op it ,@(cdr args))))

  (mac afold (op id . args)
    (if (no args)
         id
        `(let it ,(car args) (,op it (afold ,op ,id ,@(cdr args))))))
pg notes at the bottom of arc.arc:

  ; idea: anaph macro so instead of (aand x y) say (anaph and x y)
Hence the name and structure of these macros. As noted in On Lisp, there are a bunch of different anaphora cases. E.g.,

  (aand a b c)

  ==

  (let it a
    (and it
         (let it b
           (and it c))))
whereas

  (awhen a b c)

  ==

  (let it a
    (when it b c))
These correspond respectively to the :all and :first keywords of defanaph in On Lisp (page 223). Lacking keywords in Arc, I just use anaph for the :all case and anaph1 for :first (1 actually serves a semantic purpose in the name, unlike anaphex1, anaphex2, and anaphex3 in On Lisp).

For example,

  arc> (anaph list 1 (+ it 2) (* it 3))
  (1 3 9)
  arc> (anaph1 if 'foo (string it "bar") 'baz)
  "foobar"
However, notice that anaph will expand into a form that evaluates all of the arguments.

  arc> (ppr:macex1 '(anaph list 1 (+ it 2) (+ it 3)))
  (withs (gs2041 1 it gs2041)
    (withs (gs2042 (+ it 2) it gs2042)
      (withs (gs2043 (+ it 3) it gs2043)
        (list gs2041 gs2042 gs2043))))t
So, this will break for aand.

  arc> (anaph and nil (prn "this shouldn't print"))
  this shouldn't print
  nil
Hence, afold is modeled more closely to aand's definition in arc.arc, but generalizes it into a right fold (http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29). This makes (afold and t ...) slightly different from aand, since we need to supply the identity element, lest afold make assumptions about op having a zero- or one-argument case.

  arc> (afold and t nil (prn "this shouldn't print"))
  nil
  arc> (aand nil (prn "this shouldn't print"))
  nil
  arc> (afold and t 'a 'b)
  t
  arc> (aand 'a 'b)
  b
But, you could certainly define all sorts of other afold variants based on how to handle zero/one-argument cases alone.

I didn't bother with the :place keyword from On Lisp because I didn't find it very interesting.



1 point by akkartik 3098 days ago | link

This post got me rereading some of on lisp around page 223, and I noticed asetf, an anaphoric setf that you'd use instead of zap.

From page 236: "One of the advantages of asetf is that it makes it possible to define a large class of macros on generalized variables without worrying about multiple evaluation." So you could use it instead of once-only vars (http://arclanguage.org/item?id=13342) in some situations.

-----