Arc Forumnew | comments | leaders | submitlogin
3 points by rocketnia 4933 days ago | link | parent

I like your approach a lot, aw, but I too noticed this issue. I think it can be overcome just by changing the idiom slightly.

First, some definitions:

  (def fn-latemac (mac-getter)
    (annotate 'mac
      (fn args `(,(mac-getter) ,@args))))
  
  ; Not to be hypocritical, let's implement 'latemac as if by using
  ; 'latemac.
  (mac latemac (globalvar)
    `(,(fn-latemac:fn () fn-latemac) (fn () ,globalvar)))
Now we can define your example 'foo and 'bar like this:

  (mac foo ()
    `(,latemac.do
       (,latemac.prn "this is macro foo expanding into bar")
       (,latemac.bar)))
  
  ; Oops, now let's define 'bar. Go go, late binding!
  (mac bar ()
    `(,latemac.prn "yo, this is macro bar"))
As you can see below, this already works in the current version of ar. ^_^

(For future reference, I'm using https://github.com/awwx/ar/commit/c375d77bd2dbf6ca8850fda5f6.... )

  arc> (foo)
  this is macro foo expanding into bar
  yo, this is macro bar
  "yo, this is macro bar"
  arc>
    (def bar ()
      (prn "hi, this is bar"))
  *** redefining bar
  #<procedure:g1590>
  arc> (foo)
  this is macro foo expanding into bar
  hi, this is bar
  "hi, this is bar"
Essentially, these are hygienic macros at this point. They use the syntactic closure technique for hygiene, in this case implemented using regular old lambda closures. ^_^ A syntactic closure approach has undesirable properties like making the expansion hard to code-walk or serialize, but those activities seem rare enough anyway, probably because they're already difficult. I think this'll do just fine as far as modules go.