From: Rainer Joswig
Subject: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <joswig-A66075.00571524112007@news-europe.giganews.com>
I was just thinking about that topic and had some argumentation idea.
Guess that's not new, but it still could be handy if
your Ruby friends ask you why you need macros when Ruby
has blocks and Ruby can do all the cool things.

Often people ask why you need macros when you have blocks
(anonymous functions, closures). Typical example is:

(with-open-file (stream "/tmp/foo")
  ...
  (process-stream stream)
  ...
  )

This can easily be written in languages like Ruby using
blocks. Lisp can do that too:

(call-with-open-file
  (lambda (stream)
     ...
     (process-stream stream)
     ...
     )
  "/tmp/foo")

You would need to define a function CALL-WITH-OPEN-FILE,
but that's trivial.

The macro version saves some typing and should be more readable.
But from a runtime perspective they are similar.
The function version has the advantage that it could be
more debug-friendly and could be changed later (or
even enhanced by ADVICE).

So, is that all? Do we need macros?


Now, the real drawback for some situations is that the
function can notinfluence the compilation of
the argument functions. All it can do is to set
up some runtime environment (error handlers, special
variables, unwind-protect, catch, ...) and
then call the argument function.

Above anonymous function will be compiled as normal.
The function CALL-WITH-OPEN-FILE has no influence on that.
All it can influence is the runtime environment.

Now, WITH-OPEN-FILE is a macro. At compile time it gets
the enclosed code passed. The macro then returns new
code, which is then compiled. What does that mean?


a) the generated code will also create the necessary
   RUNTIME effects (error handlers, special
   variables, unwind-protect, catch, ...)

b) WITH-OPEN-FILE can determine at COMPILE-TIME what
   code gets generated and can change the environment,
   so that the compilation of the enclosed form gets
   effected.

So, b) is new. What kind things could be added at compile time?

* with symbol macros, the interpretation of
  symbols by the compiler can be changed.

  an example for that is the WITH-SLOTS macro.

  (with-slots (foo bar) some-object (list foo bar))

  The symbols foo and bar will be expanded to something
  different. The symbols will be expanded into a call
  using SLOT-VALUE. 
  
* with local macros, the interpretation of
  forms can be changed.

* we can inform the compiler to locally use a different
  optimization strategy.

* we can introduce symbols that can be used inside the code

* we can walk the code using a code walker
  and change it where we want it deep down.
  The returned code then gets compiled.

* we can do all kinds of arbitrary code transformations
  deep in the enclosed code.

So the real difference is that the macro can set up
an compile-time environment that effects the code generation for
the enclosed forms. These changes can have all kinds of effects,
since the macro can do arbitrary computation at compile-time.
A function can't do that. The function
only can change the runtime environment and
call the block it gets at runtime. But the block
is just data for the function.

From: Griff
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <fbbbed9a-37f1-4599-9586-ba42fc97abb8@r60g2000hsc.googlegroups.com>
On Nov 23, 5:57 pm, Rainer Joswig <······@lisp.de> wrote:
> I was just thinking about that topic and had some argumentation idea.
> Guess that's not new, but it still could be handy if
> your Ruby friends ask you why you need macros when Ruby
> has blocks and Ruby can do all the cool things.

Ask your Ruby friends to show you how to implement a 'for' loop in
Ruby!
From: Rainer Joswig
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <joswig-CFE7F4.10535924112007@news-europe.giganews.com>
In article 
<····································@r60g2000hsc.googlegroups.com>,
 Griff <·······@gmail.com> wrote:

> On Nov 23, 5:57 pm, Rainer Joswig <······@lisp.de> wrote:
> > I was just thinking about that topic and had some argumentation idea.
> > Guess that's not new, but it still could be handy if
> > your Ruby friends ask you why you need macros when Ruby
> > has blocks and Ruby can do all the cool things.
> 
> Ask your Ruby friends to show you how to implement a 'for' loop in
> Ruby!

That's simple if you pass the step-fn as a block
and call it. Similar to this:

? (ffor 0 10 #'print)

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
NIL

Above can be easily defined as a function.
From: Vesa Karvonen
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <fi91ug$amu$1@oravannahka.helsinki.fi>
Rainer Joswig <······@lisp.de> wrote:
> In article 
> <····································@r60g2000hsc.googlegroups.com>,
>  Griff <·······@gmail.com> wrote:
> > On Nov 23, 5:57 pm, Rainer Joswig <······@lisp.de> wrote:
> > > I was just thinking about that topic and had some argumentation idea.
> > > Guess that's not new, but it still could be handy if
> > > your Ruby friends ask you why you need macros when Ruby
> > > has blocks and Ruby can do all the cool things.
> > 
> > Ask your Ruby friends to show you how to implement a 'for' loop in
> > Ruby!

> That's simple if you pass the step-fn as a block and call it. [...]

Indeed, it is easy to implement a fairly expressive combinator library
for expressing loops.  I wrote one in Standard ML a couple of years
ago:

  http://mlton.org/ForLoops

The combinators on that page cannot express "zip" or parallel
iteration over multiple sequences, but that can be done using streams
[1].  With an optimizing compiler, the generated code will be about as
efficient as a hand written loop.

-Vesa Karvonen

[1] http://mlton.org/pipermail/mlton-user/2007-April/001091.html
From: Pascal Costanza
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <5qr66uF117m5hU1@mid.individual.net>
Vesa Karvonen wrote:
> Rainer Joswig <······@lisp.de> wrote:
>> In article 
>> <····································@r60g2000hsc.googlegroups.com>,
>>  Griff <·······@gmail.com> wrote:
>>> On Nov 23, 5:57 pm, Rainer Joswig <······@lisp.de> wrote:
>>>> I was just thinking about that topic and had some argumentation idea.
>>>> Guess that's not new, but it still could be handy if
>>>> your Ruby friends ask you why you need macros when Ruby
>>>> has blocks and Ruby can do all the cool things.
>>> Ask your Ruby friends to show you how to implement a 'for' loop in
>>> Ruby!
> 
>> That's simple if you pass the step-fn as a block and call it. [...]
> 
> Indeed, it is easy to implement a fairly expressive combinator library
> for expressing loops.  I wrote one in Standard ML a couple of years
> ago:
> 
>   http://mlton.org/ForLoops
> 
> The combinators on that page cannot express "zip" or parallel
> iteration over multiple sequences, but that can be done using streams
> [1].  With an optimizing compiler, the generated code will be about as
> efficient as a hand written loop.

That's the catch. Macros are a hook into the compiler, so they give you 
the possibility to express such optimizations yourself, including for 
cases that the compiler itself didn't anticipate.

A very nice contribution here is Common Lisp's notion of compiler macros 
- they allow you to define a concept in terms of (first-class) 
functions, but you can also define optimizations for the common cases at 
the same time, without requiring users to decide whether they want to 
use the functional or the macro version.

They are not perfect, but much better than nothing.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Griff
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <b0c2c165-6750-48a3-b92a-262143ac17f4@w34g2000hsg.googlegroups.com>
On Nov 24, 3:54 am, Rainer Joswig <······@lisp.de> wrote:
> > Ask your Ruby friends to show you how to implement a 'for' loop in
> > Ruby!
>
> That's simple if you pass the step-fn as a block
> and call it. Similar to this:

Sorry I my post was vague.

I didn't mean "implement something like a for loop", I meant implement
a (new) 'for' loop just like the one that Ruby provides for you.

For example:

new-for i in 1..10
    puts i
end
From: Kaz Kylheku
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <87c39895-c7d9-44bc-9df1-6a75b2c3332e@s12g2000prg.googlegroups.com>
On Nov 23, 3:57 pm, Rainer Joswig <······@lisp.de> wrote:
> I was just thinking about that topic and had some argumentation idea.
> Guess that's not new, but it still could be handy if
> your Ruby friends ask you why you need macros when Ruby
> has blocks and Ruby can do all the cool things.
>
> Often people ask why you need macros when you have blocks
> (anonymous functions, closures).

The obvious answer is that without macros, all available syntax
consists of special forms that are coded into the language
implementation. The code which provides these forms resembles macros,
except that it's inconvenient, impossible or impractical for the user
to extend. So arguably, at least the user interface part of Ruby
blocks is provided by something which is /like/ macros, but
unavailable to the user. The Ruby programmer can't create some new
syntax which resembles Ruby blocks, but does something different.

Thus Ruby blocks do not eliminate syntactic recognition and
translation, but rather depend on it for their existence.  The
remaining argument against macros must then be around the idea that
the user doesn't need them, because a perfect set of special operators
has been provided already.

The problem is that without macros, a program has to be written
directly in the available special forms. Macros are the only tool
which allow any such program to be compressed into a smaller syntax
which takes advantage of regularities in that program which are not
compressible by any other means.

After all possible means for factoring the regularities in a program
have been exhausted using the available special operators, further
gains can only be made through maros.

For instance, consider the argument that Ruby-like blocks eliminate
the need for macros. For this to be true, it would have to be the case
that after any given program has been maximally factored for terseness
and clarity by means of blocks, there necessarily do not remain any
further regularities which can be reduced by macros.

That's not to mention that macros are sometimes the best tool for the
job even if there is some other way to do it, and not a last resort.
From: ··········@aol.com
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <a5a95f2b-0245-4877-ae20-9189e3d4dd52@d27g2000prf.googlegroups.com>
On Nov 23, 11:37 pm, Kaz Kylheku <········@gmail.com> wrote:
> On Nov 23, 3:57 pm, Rainer Joswig <······@lisp.de> wrote:
>
> > I was just thinking about that topic and had some argumentation idea.
> > Guess that's not new, but it still could be handy if
> > your Ruby friends ask you why you need macros when Ruby
> > has blocks and Ruby can do all the cool things.
>
> > Often people ask why you need macros when you have blocks
> > (anonymous functions, closures).

Well, I answered this back in September, adequately and completely-
nothing remained to be said ;). Still, Kaz picks up the torch. (BTW,
part of the answer is that you don't- you really don't have to use
macros. In fact. you really don't have to use anonymous functions. You
don't, in fact, have to use functions at all. Or methods. Or Gosubs. I
swear to God, I wrote some stuff in MS Basica that many [current]
professional programmers couldn't replicate using modern "concepts"
like abstraction and encapsulation. I didn't know any better. Are you
now convinced that MSBasica is the Language of the Future? If so, I
fear you are lost in the bogs of Turing, not to be redeemed...)

> The problem is that without macros, a program has to be written
> directly in the available special forms.

Everything surrounding this quote is verbiage. Good verbiage, of the
sort I might produce, but verbiage. To explain further is to risk
being Harroped.

Just to be clear- there is nothing you can do with macros that could
not be more cleanly implemented as a language feature in some
language. The point is that sometimes you want to do something with a
language, and you are not, in fact, its implementor[1]. I know it
sounds stupid (I mean, who would want to do something a library didn't
cover- not "Web 2.0" at all, cluck. cluck). Shoo hen, shoo.

There is no need for you to program in CL. There is no need for your
protégé to program in CL. If you don't like it you can choose another
language. There's enough info out there that you shouldn't have to ask
other people to convince you one way or another. But seriously.. the
Lisp mafia should shut up and code, and everyone else should stay away
unless they want to swear on their mother's puta.

[1] Yes, just like the old He-Man cartoons, it is Skeletor/Sodomotor/
Implementor, etc.
From: ··········@aol.com
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <015b0051-f2f0-4d00-b063-e747b2b2b995@e1g2000hsh.googlegroups.com>
I should add, of course, that I don't mean this as a slap at Rainer...
just at his hypothetical questioner. I hope that was clear, but I am
not sure, so...
From: Maciej Katafiasz
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <fi7rd5$qfl$1@news.net.uni-c.dk>
Den Sat, 24 Nov 2007 00:57:16 +0100 skrev Rainer Joswig:

> Now, the real drawback for some situations is that the
> function can notinfluence the compilation of
> the argument functions. All it can do is to set
> up some runtime environment (error handlers, special
> variables, unwind-protect, catch, ...) and
> then call the argument function.

A particularly important kind of evaluation is no evaluation. Real macros 
enable you to add new operators[1] trivially whilst preserving all the 
important semantic properties of operators, like short-circuiting, well-
defined and non-standard evaluation order, non-evaluating forms and more. 
You can do this trivially:

(defmacro none (&body body)
  `(not (or ,@body)))

but you can't add real syntactic forms with blocks that wouldn't be just 
camouflaged function invocations. Ruby gets around this with its keyword 
arguments it lifted from Lisp to a certain extent, still, that only gets 
you so far.

Cheers,
Maciej

[1] Operators meant mostly in the sense of languages that distinguish 
syntactically between operators and function calls, which includes all 
the bastard offspring of Algol and C. Special forms would be an 
appropriate term for CL, if it weren't for the fact that CLHS explicitly 
enumerates all of them and disallows users from creating new ones.
From: Russell McManus
Subject: Re: Macros vs. passing anonymous functions, argumentation
Date: 
Message-ID: <87k5o7og44.fsf@thelonious.cl-user.org>
Rainer Joswig <······@lisp.de> writes:

> Now, the real drawback for some situations is that the
> function can notinfluence the compilation of
> the argument functions. All it can do is to set
> up some runtime environment (error handlers, special
> variables, unwind-protect, catch, ...) and
> then call the argument function.

You are on to something there.  Macros shine most brightly when used
as mini-compilers.  The simplest example that I can thing of is HTML
generating macros, which optimize by coalescing adjacent strings at
compile time.  I don't think it's easy to do something similar in
Ruby.

I've seen Perl programs that do compile time programming, but it looks
like black magic.  So even good Perl programmers very rarely use this
technique.  In Lisp it's just another well-worn wrench in the software
toolbox...

-russ