[R6RS] Internal DEFINE vs. macros

dyb at cs.indiana.edu dyb
Tue Apr 26 01:32:03 EDT 2005


> The problem is that you haven't convinced me that internal DEFINE,
> INCLUDE, and internal DEFINE-SYNTAX are a great help writing clearer
> code.  You seem to regard this as an obvious axiom, but it isn't
> obvious to me.

Mixed internal definitions are strictly more expressive, since they permit
mutually recursive variable, syntax, and in Chez Scheme at least, module,
record, and class definitions.  In my experience, internal definitions
also lead to code that is more pleasant to look at, whereas let-syntax,
letrec-syntax, and even letrec lead to code that is more deeply nested
and awkwardly formatted.  It's also easier to pull a definition or
set of definitions out of a local scope to test them interactively.
For these reasons, I usually use internal definitions even where one of
the other local binding constructs would also work.

> (I'm not convinced of the opposite, either, but I sure
> feel uneasy at this point.)

I doubt I can make you feel less uneasy, and I am unlikely to come
around to your point of view.  If it comes to a choice, I'd definitely
choose to eliminate let-syntax and letrec-syntax rather than internal
syntax definitions.  Can't we just support both forms so that you can
use let-syntax/letrec-syntax and I can use internal syntax definitions?

> - I avoid internal DEFINE about the same way I avoid DO.  When I do, I
>   often make mistakes because the semantics isn't clear to me.

This is ironic.  Although the semantics of do is clear to me, I avoid
both do and letrec/letrec-syntax (partly) because they don't scale.
do doesn't scale to nontail recursion and multiple termination and
recursion conditions, and letrec/letrec-syntax don't scale to mutual
recursion among different kinds of bindings.

> - I almost invariably find code that is less deeply nested easier to
>   read than more deeply nested code.  (And I usually use the module
>   system to make my code less deeply nested.)  This also means
>   less internal definitions in many circumstances.

This is also ironic.  As I said above, another reason I use internal
definitions is to avoid too much nesting.  Replacing a sequence of
variable and syntax definitions with letrec-syntax and letrec requires
at least two levels of nesting, one for the letrec and one for the
letrec-syntax, and may require even more.

> ... So I'm hoping you'll indulge me and
> help me out with a few examples :-)

You can find some examples of internal syntax definitions in the source
files for SWL, which you can download from

  http://scheme.com/csv6.9c/swl0.9y-src.tar.gz

If you grep for '^  *(define-syntax' in all of the .ss files contained
within swl0.9y you should find most of the internal define-syntax forms.
Doubtless some fall into your "top-level of a module" category and
most of the rest could be recoded using let-syntax or letrec-syntax,
but see particularly line 227 of swl0.9y/src/swl/dialog.ss, where the
ability to express mutual recursion among variable and syntax-definitions
is exploited.

Also look for derived definitions, like define-constant, that we had to
define only once whether we want to use them at top level or internally.
That is, we don't have to have a define-constant for top level code and
a separate let-constant for internal code.

Incidentally, I'm still hoping to preserve the property that we can
compose language constructs in arbitrary ways; that's another reason
I'm not interested in restricting define-syntax, or any other construct,
to the top level or some top-level module construct that has no internal
counterpart.

Kent


More information about the R6RS mailing list