

Is Scheme as good as Common Lisp? - Tichy

I think Scheme doesn't have the all-powerful Macros, so would one be missing out on all the LISP goodness for choosing Scheme? <p>How usable are Macros, anyway? Does their use tend to produce readable code?
======
pg
Scheme has a way of defining macros that's supposed to be better than old-
fashioned defmacro. These "hygienic macros" seemed to a lot of people (though
not me) to be a good idea when they were invented. They got into the Scheme
standard then. I think people don't like them so much now, but once something
gets into a standard it's impossible to get it out.

However (a) all the Scheme implementations I know of have implemented classic
defmacro macros as well, and (b) if one hadn't, you could easily write it
yourself. So in practice there's not much of a decision to make.

The Arc implementation you're using to read this is written on top of Scheme.
Currently Mzscheme.

~~~
omouse
Hygienic macros do seem to be a good idea: "Hygienic macros are macros whose
expansion is guaranteed not to cause collisions with existing symbol
definitions." (from Wikipedia, <http://en.wikipedia.org/wiki/Hygienic_macro>)

What are the disadvantages? Is there any reason to dislike defining syntax
rules?

~~~
abstractbill
One reason I've heard is that sometimes you actually _want_ those collisions
(I haven't come across a good example though - anyone know of one?).

For me the reason is just that defmacro is easier to read.

~~~
pg
here's one:

    
    
     (defmacro aif (test then &optional else)
       `(let ((it ,test))
          (if it ,then ,else)))

~~~
edw
In Scheme, the cases where one would use anaphoric IF can be handled using a
COND clause with a "=>":

    
    
        (cond ((assoc 'key collection)
               => (lambda (it) (do-something-with it)))
              (else
                  (alternative)))
    

Alternatively, if you really wanted to create an AIF macro, you could use
SYNTAX-RULES to create something that sugared up the above thusly:

    
    
        (aif it (assoc 'key collection)
             (do-something-with it)
             (alternative))
    

Or you could, going outside the standard, use SYNTAX-CASE (ugh, in R6RS) or
one of the other non R5RS approaches to macros e.g. syntactic closures[1] that
don't throw out the macro hygiene baby with the occasional slight
inconvenience bath-water.

I'm a bit of a reformed macrologist; if I get an idea for a cool macro, I try
to see how far I can take a non-macrotic version and compare that to what the
syntactically-sugared version would be like. Most of the time, I wind up not
bothering with a macro. I put macros in the same category as EVAL: If you
think you need to use a macro, think again.

[1]: (<http://community.schemewiki.org/?syntactic-closures>)

~~~
brlewis
You are right about cond, but don't forget that cond and other Scheme syntax
can be implemented as hygienic macros:

[http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z...](http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-
Z-H-10.html#%_sec_7.3)

Macros are a build-your-own-language construct, but to a certain extent so are
functions. I agree that one should try functions first, but would not go so
far as to put macros in the same category as using eval.

~~~
edw
I thought a lot of Scheme implementations define IF in terms of COND. Is there
some reason you're pointing this out?

I should have been more detailed and noted that on the "by all means use it"
vs. "if you think you need it, think again" continuum, EVAL requires IMO more
justification than a macro. The source of my concern over macros is that when
designing them, care needs to be taken to clearly communicate their semantics,
which is best done IMO by following the established conventions of the
language and whatever other macros the user is expected to be familiar with.

~~~
brlewis
You pointed out one could achieve much the same result as the aif macro by
using cond. I wanted to point out that cond itself is an example of the power
of macros.

~~~
edw
My point was more than one isn't usually missing much by being limited to
writing hygienic macros. I don't think anyone is disputing the power of
macros; it's the power/cost of hygiene violation that people are discussing.

Someone could give a "trust the programmer" argument for making unhygienic
macros available in a language, but that nostrum is problematic because there
are two programmers: the macro writer and the macro user. It's harder than you
think to write a macro using DEFMACRO that always behaves the way a user might
expect it to behave, and as a user of a macro, you need to wonder how hard the
macro writer worked to protect you -- something that I don't like as a fan of
black boxes.

------
omouse
Macros produce kickass code: <http://neverfriday.com/blog/?p=10#more-10>

If I didn't create a string-case= macro, I would have to write the final
expression over and over again. With multiple string-case matches I would have
to write string=? many many times:

    
    
     (cond ((or (string=? "hello" my-string)
                (string=? "world" my-string))
            (print "match")))
    

To do that with the string-case= macro:

    
    
     (string-case= my-string
       (("hello" "world")
        (print "match")))
    

Saves quite a bit of typing and now I have a good example of why macros are
good to have around :D

 _edit: formatting ftw._

~~~
brlewis
If you put spaces in front of your code, news.yc will indent nicely.

    
    
     (cond ((or (string=? "hello" my-string)
    	    (string=? "world" my-string))
    	(print "match")))
    
     (string-case= my-string
       (("hello" "world") (print "match")))
    

------
brlewis
R5RS hygienic macros qualify as LISP goodness, but a lot of Scheme
implementations also implement defmacro (like CL) and/or syntax-case.

Use of macros makes the code reflect the programmer's thinking about the
problem domain. Whether this is readable or not depends on the programmer.

------
davidw
Yes, but both are widely considered inferior to Visual Forth ++.

