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

I think there is one way to consider Arc to be a language with good hygiene: We can program so that if we ever use a name as a global variable, we never use it as a local variable, and vice versa. As long as an Arc problem follows this rule and the usual (w/uniq ...) idiom, it won't encounter hygiene issues.

Paul Graham has this to say about hygiene in the tutorial:

  Some people worry unduly about this kind of bug.  It caused the
  Scheme committee to adopt a plan for "hygienic" macros that was
  probably a mistake.  It seems to me that the solution is not to
  encourage the noob illusion that macro calls are function calls.
  People writing macros need to remember that macros live in the land
  of names.  Naturally in the land of names you have to worry about
  using the wrong names, just as in the land of values you have to
  remember not to use the wrong values-- for example, not to use zero
  as a divisor.
However, he's only careful about one direction of variable capture. Here's one example from the tutorial where he doesn't mind capturing the names let, repeat, push, and rev:

  (mac n-of (n expr)
    (w/uniq ga
      `(let ,ga nil
         (repeat ,n (push ,expr ,ga))
         (rev ,ga))))
I think he gets away with this because he's following that rule I mentioned, keeping a careful separation between the names of locals and globals.

It seems we don't particularly follow that rule here on the Arc Forum. For instance, a few of us have agreed that a certain behavior in Arc 3.1 is a bug: When we make a function call to a local variable, we don't want a global macro of the same name to take effect, which is what happens in Arc 3.1. If we were keeping locals and globals separate, we wouldn't even encounter this problem.

Which means that if we want to write macros that are hygienic, we can't write them in quite the way we see in arc.arc or the tutorial. If we're dedicated to hygiene, we might even want to rewrite arc.arc to fix its hygiene issues... but that's practically the whole language, so it effectively starts to be a new language project. The Anarki arc2.hygiene branch, Penknife, ar, Semi-Arc, and Nulan are several examples of Arc-based or Arc-inspired projects that pursued some kind of hygiene.

If we don't mind the lack of hygiene in arc.arc but only care about proper hygiene for our own new macros, it is possible to be diligent about hygiene in plain Arc 3.1 or Anarki:

  (mac n-of (n expr)
    (w/uniq ga
      (rep.let ga nil
         (rep.repeat n (rep.push expr ga))
         `(',rev ,ga))))
Coding this way looks a little arcane and loses some of Arc's brevity, but one of the techniques here is to embed a the rev function into the syntax as a first-class value. By putting most of the macro implementation into an embedded function, it can become rather familiar-looking again:

  (mac n-of (n expr)
    `( ',(fn (n expr)
             (let a nil
               (repeat n (push (expr) a))
               rev.a))
       ,n
       (fn () ,expr)))
Here's a macro that makes this even more convenient:

  (mac qq-with args
    (let (body . rev-bindings) rev.args
      (let (vars vals) (apply map list (pair rev.rev-bindings))
        `(',list `',(fn ,vars ,body) ,@vals))))
  
  (mac n-of (n expr)
    (qq-with n n expr `(fn () ,expr)
      (let a nil
        (repeat n (push (expr) a))
        rev.a)))
I think if I programmed much in Arc again, I'd start by defining that macro or something like it. :)

As it is, right now I'm just settling into a macro system I designed. I don't have convenient gensym side effects like Arc does, and I want the generated code to be serializable (not containing opaque first-class functions), so my options are limited. I still can and do implement macros, but the implementation of each macro is pretty verbose.



1 point by kinnard 3211 days ago | link

I'm still learning lisp and haven't fully wrapped my head around macros. So the hygienic vs unhygienic debate is still more or less opaque to me :D

-----