Arc Forumnew | comments | leaders | submitlogin
3 points by stefano 5954 days ago | link | parent

Functions can be passed around, so the lexical scope is really handy in this case. Macros, instead, are expanded in place: e.g. the macro

  (mac m (a)
    `(f ,a))
"f" is just a symbol. In hygienic macros f would be changed to some unique symbol (actually you wouldn't write such code in a hygienic macro if your intent was to make the expansion call f). In a standard macro system, you voluntarily capture the symbol 'f, maybe because it will be bound to a function at runtime. In that example f doesn't have dynamic scope nor lexical scope: it is just a symbol that the macro has put in the result of its computation. Its meaning (variable or not, lexical scope or not) will be decided on the successive compilation pass.


1 point by nlavine 5953 days ago | link

Yes, exactly. I see why that is true. But think about a parallel function:

  (def n (f a)
    (f a))
In the function, you can pass f as an argument to call. In a macro, f is passed implicitly in the environment the macro is expanded in. The method of passing f to the macro m seems very much like using dynamic scoping to pass arguments to functions. My question is, what about a macro system where you could pass real arguments to macros? I.e., other macros (or functions, etc.)? What makes these things different?

-----

2 points by stefano 5952 days ago | link

> what about a macro system where you could pass real arguments to macros?

Like this

  (mac n (f a)
    `(,f ,a))

  (n [+ _ 1] 9) 
  ==> 10
where you pass a form that is then evaluated by the macro, or did you mean something else? Macros' arguments aren't evaluated, so you can pass only forms. To pass the result of a computation in CL (not in Arc) you can use read macros, that are evaluated before macro expansion time:

  (n #.(computation) 9)
This is quite unusual, because macros are intended mainly to modify the syntax, so it's quite natural to make them work on the syntax itself (i.e. the forms).

-----

1 point by nlavine 5952 days ago | link

Ah, I see this. I think I have been thinking of macros differently than you have (and probably wrongly). I suppose lexical scoping for macros would make the most difference in the case where a macro expands to a function call, like this:

  (let x 0  ; call (count) to keep a count of things
    (def count () (set x (+ x 1))))

  ; count-ops: count how many lines of code you run.
  (mac count-ops body
    (if body
        (cons (car body)
              (cons '(count)
                    (count-ops (cdr body))))
        '())

  (def foo ()
    (count-ops ; this count-ops call fails
      (with (count 1 step 2)
         ; do some loopy stuff here
      )))
If that's not a compelling example, pretend that count-ops is inserting an interrupt check between every two lines of code. Why is dynamic scoping better for cases like these?

As for real arguments to macros, yes, I meant something like the CL stuff. You're right, though, that macros modify syntax, and I wasn't thinking about them that way. Two posts up you said that macros are "expanded in place". I think that you were thinking about the effect macros have on the code they're called on, whereas I was thinking about the call to the actual macro procedure, and passing arguments to it.

-----