I believe the short answer to your questions is that macros and other
special forms could be first-class objects--there is no semantic reason to
forbid it--but that compiler writers would scream and run away in horror.

(To begin with, any expression of the form ((car x) y ...) could be a macro
call, and hence the arguments "y ..." cannot be evaluated until it is
determined--at run time--that (car x) is in fact a function.  Furthermore,
consider this case:

(let ((x (cons y z)))
  ((car h) (cdr x))
  (+ 4 (car x)))

(car h) could conceivably be a macro that would extract the "x" from the
"(cdr x)" expression and produce "(set-car! x 8)" or something like that.
Therefore, it would be unsound for the compiler to simply replace "(car x)"
with "y".  --Calling functions from data structures, as in "((car fs) a
b)", seems a rare thing to do, but now we must realize that global
variables can usually be modified too, and if ((car mac-list) x) always
gets the current car of the mac-list (as opposed to extracting the car once
and assuming it'll always remain the same), it would be terribly
inconsistent if (f x) did not get the current value of f and, if it
happened to be a new macro, to expand some new code and run it.  Therefore,
the compiler must assume that even "(f (cdr x))" could actually modify the
car of x, if f might be redefined in between when this code is compiled and
when it is run.  I expect real compiler writers could produce more common
and compelling examples of important optimizations that become
impermissible (or incredibly difficult) in the presence of first-class
macros (loop invariants come to mind).

I believe it is nevertheless possible--using partial evaluation, rules
about when threads learn of updated global variables, and a system of
invalidating and recompiling functions--to have efficient compiled code and
first-class macros, but I don't think such a system exists right now.)

You might find some Scheme or Lisp interpreters that provide macros and
special forms as first-class objects--in fact, I have an Arc interpreter
that does just this--but don't expect to find it in compilers, or language
standards, any time soon.

--John Boyle
*Science is what we understand well enough to explain to a computer. Art is
everything else we do.* --Knuth


On Thu, Apr 25, 2013 at 1:43 PM, Stephen Lewis
<[email protected]>wrote:

> In studying the draft report and the various implementations, I have formed
> several questions on which I would like the opinion of an expert.
> If this is the wrong place to ask such questions please suggest a more
> appropriate forum.
>
> In the R7RS standard, are macros (i.e syntax objects) considered to be
> first-class objects?
> [First-class object being an entity that can be constructed at run-time,
> passed as a parameter, returned from a subroutine, or assigned to a
> variable.]
>
> For example would these examples be considered to be standard compliant
> R7RS
> Scheme? The implementations to which I have access do not all behave
> in the same way.
>
> Storing a syntax object in a variable?
>
> (define myand and)
>
> Calling my stored object as I can the original?
>
> (myand #t (+ 1 2 3))
>
> Returning a syntax object from a procedure?
>
> (define (return-op) and)
> (define myop (return-op))
> (myop #t (+ 1 2 3))
>
> May I call a syntax in the same way I call a primitive procedure?
>
> (and #t (+ 1 2 3))
> ((return-op) #t (+ 1 2 3))
> ((and and) #t (+ 1 2 3))
>
> I have read the R7RS draft and I am having difficulty answering these
> questions.
> I find that there are "Primitive Expressions" and "Derived Expressions" and
> that derived expressions "can instead be defined as macros" but this does
> not
> seem to be a requirement. The description of a procedure call although in
> the Primitive Expression section does not appear to exclude syntax objects.
>
> "A procedure call is written by enclosing in parentheses an expression
> for the procedure to be called followed by espressions for the arguments
> to be passed to it."
>
> An expression that returns a syntax would appear to be allowed.
>
> (define ops `(,* ,and))
> ((car ops) 2 3)
> ((cadr ops) #t #f)
>
> What about (and and) which is an expression that returns a syntax.
>
> ((and and) #t (+ 1 2 3))
>
> The WG1 charter asserts that "Self consistency is an important objective,"
> and yet the boolean operators and arithmetic operators do not behave
> consistently. In particular as a user of the language it is not obvious
> which functions have been implemented as primitives and which as a syntax.
>
> It appears to be valid to implement the "and" function as a primitive or
> as a macro and curiously the boolean "not" function is listed with the
> Standard Procedures making it inconsistent with the other boolean
> operators.
>
> There is another situation in which the difference between primitive
> procedures and syntax objects makes itself a nuisance and that is in
> short-cicuit evaluation of the boolean operators. In the following
> expression one might think that the "never" object was not evaluated:
>
> (and #f never)
>
> and yet if the "never" object is a syntax it would seem that it is
> evaluated.
>
> (and #f and)
>
> If these topics have been discussed previously I apologize and please
> refer me to the earlier discussion,
>
> Stephen Lewis
>
>
> _______________________________________________
> Scheme-reports mailing list
> [email protected]
> http://lists.scheme-reports.org/cgi-bin/mailman/listinfo/scheme-reports
>
_______________________________________________
Scheme-reports mailing list
[email protected]
http://lists.scheme-reports.org/cgi-bin/mailman/listinfo/scheme-reports

Reply via email to