[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
applicability of "syntax" constructs
I'd like to solicit views on the question of application of
macros and their first- vs. second-class status in Scheme. ...
I suspect that the subject is highly controversial, but these are my
views on the matter:
1)
There is a traditional pun used in Lisp. The syntax for special forms
and combinations (procedure calls) is the same. This results in a a
fair amount of convenience, some power, and a great deal of confusion.
A perhaps wiser decision would have been to mark special forms with
square brackets (or squiggly braces, or something like that), rather
than the parentheses used for combinations, but the resulting language
would not be a Lisp.
Your problem arises from trying to view special forms as combinations
(due most likely to this pun), and therefore inquiring about the
status of their (nonexistent) operator.
(if <pred> <conseq> <alternative>)
is part of the syntax of the language. IF is not a "special" operator
which does something "strange". The whole expression (form) is special,
and the only thing in common between it and a combination is the
similarity in surface syntax.
In the same way that no C programmer would think of applying "while"
or "if" to arguments (let alone pass them around), no Scheme programmer
should think of invoking "if", "cond", "lambda", "or", or user defined
special form keywords. The keywords mean nothing by themselves, they
are as good as the parentheses that surround the form, and it makes as
much sense to talk about applying them as about applying parentheses,
semicolons, or spaces.
As far as I know, none of the major implementations of Scheme match
the popular evaluation model you suggest. IF, COND, OR, etc can be
viewed as part of the compiler or preprocessor, and are long gone by
the time the issue of where to find X arises.
In MIT Scheme, which is consistent with this philosophy, the question
of whether IF is APPLICABLE?/PROCEDURE? cannot arise. IF is
"nothing", and the expression
(procedure? if)
is in error, and in fact would cause something like
Error: Unbound variable IF
to be printed.
A different question altogether is whether special form keywords can
be valid variable identifiers, and if so, what happens in case of
conflict.
2)
The "unfortunate" fact of life is that Scheme is an applicative order
language, and some things which could be accomplished conveniently in
a normal order dialect cannot. For example, in the presence of
(define (if pred conseq alt)
(cond (pred conseq)
(else alt)))
the following expression is in error, although the intent was quite
different.
(let ((x 0))
(if (= x 0)
'INFINITY
(/ 1 x)))
To make up for this "deficiency" of the language, we "abuse" special
forms, and define a special form whose KEYWORD is "if" and
accomplishes the desired behavior, but is no substitute for a normal
order IF procedure.
Note that in your example
(apply or '(#f #f #t))
the answer is clear, but what should the answer be in
(let ((x 2))
(apply or (list (= x 2) (begin (write 4) (= x 3)))))
There are many possibilities. The main ones are:
a) 4 is never printed. This would be the case in a "normal order
Scheme". If you choose this one, you've just required APPLY to be a
normal order procedure, and similarly for most other high order
procedures. That is a valid language decision, different from that
made by Scheme's designers. While it has nicer properties than
applicative order, normal order also has some problems, not the least
of which is that no one (as far as I know) knows how to compile normal
order languages efficiently.
b) 4 is printed, and the correct "boolean" value is returned. This
leads to a very ugly semantics: For consistency, you would have
the following two expressions behave differently,
(or (= x 2) (begin (write 4) (= x 3)))
((begin or) (= x 2) (begin (write 4) (= x 3)))
which I think is worse than the original "problem".
3)
Assuming that we are happy with the fact that special forms have no
operators, (and therefore the notion of applying OR is confused), the
problem of distinguishing special form keywords from identifiers whose
values are procedures still remains. This is a matter of
readability/documentation, and a simple solution is the adoption of
conventions.
A suggestion along these lines is to use the same sort of convention
that is already informally followed for predicates (the last character
of their name is ?). For example, user defined special form keywords
could have $ as their first character. The built-in special forms
follow no such conventions, but there are few of them, and most
programmers probably remember them, so we can live with them the way
they are.