From: Eli Bendersky
Subject: A "killer" macro
Date: 
Message-ID: <1189580359.816831.175510@50g2000hsm.googlegroups.com>
Hello all,

In short: I'm looking for a "killer" macro - a macro (or a couple of
related ones) that show what Lisp can do and other languages (those
without uniform syntax) can not.

A longer version: Many contemporary languages boast their sharing most
of the functional features of Lisp. Perl, Ruby, Javascript - all have
convenient lists (or arrays), functions as first class objects,
garbage collection, dynamic typing, lexical closures. However, one
thing they lack is uniform syntax, and hence the service of a powerful
built-in macro system such as Common Lisp's "defmacro".
When confronted by fellow programmers with the question "so why is
Lisp so special", I'm looking for that short - not too hard to
understand - snippet of code that will show them *why*. I'm convinced
that such a snippet must involve macros. But all the examples I ran
into so far have been either too simple - and could be easily
implemented another way (for example with Ruby's blocks), or too
complicated.

Any suggestions for such an example ?

Eli

From: Christophe
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189582230.716693.210820@22g2000hsm.googlegroups.com>
On 12 sep, 08:59, Eli Bendersky <······@gmail.com> wrote:
> Hello all,
>
> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.
>
> A longer version: Many contemporary languages boast their sharing most
> of the functional features of Lisp. Perl, Ruby, Javascript - all have
> convenient lists (or arrays), functions as first class objects,
> garbage collection, dynamic typing, lexical closures. However, one
> thing they lack is uniform syntax, and hence the service of a powerful
> built-in macro system such as Common Lisp's "defmacro".
> When confronted by fellow programmers with the question "so why is
> Lisp so special", I'm looking for that short - not too hard to
> understand - snippet of code that will show them *why*. I'm convinced
> that such a snippet must involve macros. But all the examples I ran
> into so far have been either too simple - and could be easily
> implemented another way (for example with Ruby's blocks), or too
> complicated.
>
> Any suggestions for such an example ?
>
> Eli

Hello,

Quickly, Macro in Lisp is, in fact, a way to create your own domain
specific language.

No needs to search a long time : loop, iterate or defclass are smart
examples.

Regards,

Christophe
From: Kent M Pitman
Subject: Re: A "killer" macro
Date: 
Message-ID: <uabrs2dso.fsf@nhplace.com>
Christophe <····················@birdtechnology.net> writes:

> No needs to search a long time : loop, iterate or defclass are smart
> examples.

(And the error handling operations offer additional examples.)

Interesting that you should choose these particular choices to suggest,
because...

During ANSI CL design, the process was broken into these major
interpersonal subgroups, taking on partial design:

 - iteration [yielded LOOP]
 - object system [yielded CLOS (DEFCLASS, DEFMETHOD, etc.)]
 - errors [yielded the condition system (HANDLER/RESTART-BIND/CASE, 
     IGNORE-ERRORS, etc.)]
 - pretty printer [yielded many functions, but also some macros like
     PPRINT-POP]

and then there was a mass of small cleanups done by the compiler and
cleanup groups.  But my point is that the large shifts in language
were prototyped by subgroups, and generally delivered intact with
working code that included language changes largely implementable by
users.  (The condition system design, which I headed up, for example,
had a sample implementation you can grab from 
http://www.nhplace.com/kent/CL/
It was written for an older dialect of Common Lisp [CLTL] and had no
way to hook into the system, so required minor support in that regard,
but basically was enough to give all implementors a sense of what was
being asked for without having to modify their systems.)

This ability for users to lead the development of extensions and then
propose them to the implementors, rather than to demand access to the
internals of all implementations (including proprietary ones) is very
empowering.  It's very easy to say "well, everything should be open
source and I then I could propose proper internal modifications" but
ignoring the political/business issues there and assuming they could
be magically glossed, there is still the fact that those
implementations vary widely and that's a lot to ask of an
extension--that you provide source code to disparate implementations.
You can also say that argues for one implementation, but then that
says that people who wanted smaller implementations or ones with
different performance characteristics would be out of luck.)

Macros offer the opportunity for users to contribute to language
design AND to work around the fact that at least some contributions
are likely to be rejected, since they can still use their own
extensions and can share them with others either to gain more support
or just to make a secret club of outcasts that live happily among each
other. And, incidentally, lest you think this makes a two-tier system,
in fact I think the motivation of some (perhaps many) of the designers
was that they knew THEY were not getting what they wanted (as
individuals) and were slipping in flexibilities to allow them to be
able to live happily with others' unwillingness to compromise.
From: Ken Tilton
Subject: Re: A "killer" macro
Date: 
Message-ID: <zWSFi.1562$Z%7.1523@newsfe12.lga>
Christophe wrote:
> On 12 sep, 08:59, Eli Bendersky <······@gmail.com> wrote:
> 
>>Hello all,
>>
>>In short: I'm looking for a "killer" macro - a macro (or a couple of
>>related ones) that show what Lisp can do and other languages (those
>>without uniform syntax) can not.

....

> No needs to search a long time : loop, iterate or defclass are smart
> examples.

You are absolutely right, but others will say, "Hunh? Those are part of 
the language. You think implementing classes in C++ is easy?" They won't 
get that the CLOS implementor is not doing amazing things in the 
compiler (at this point) rather merely using a tool (macros) available 
to application programmers as well.

What is needed is an example of where an application code pattern can be 
automated, and natch it has to be one where a function would not do.

kt

-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: Rob Warnock
Subject: Re: A "killer" macro
Date: 
Message-ID: <gZCdnRSVpLeFCXXbnZ2dnUVZ_q6hnZ2d@speakeasy.net>
Ken Tilton  <·········@gmail.com> wrote:
+---------------
| What is needed is an example of where an application
| code pattern can be automated, and natch it has to be
| one where a function would not do.
+---------------

One that immediately comes to mind for me is the MACRO-10
macros I used in implementing FOCAL-10 [about which I have
written too many times elsewhere], which collected dribbles
of data from the programmer [me] that was distributed
throughout the source code and planted a heavily-munged,
reformatted version of the accumulated data in a single table
at the end... AT COMPILE TIME. This is *very* convenient in
Lisp, whereas user of other languages tend to write various
external pre-processing (think "literate programming") hacks
in Perl or whatever that write out C source files, which then
get compiled/linked with or #include'd in the program.

The advantage of Lisp [or MACRO-10] macros is that the
data being accumulated can *also* be used *while* the
program text is being compiled to further conditionalize
the code being generated, something that's very hard to
do with the external pre-processing approach without having
to "generate" *all* of your program source code from a
meta-source.

[Re-implementing FOCAL in CL -- just to have an illustration
of the above -- is one of those elusive "round tuit" thingies
I haven't gotten yet. (*sigh*)]

Another good example [well, for me it is, though few non-Lispers
might appreciate it] is the definition & use of the VOP, VOP*,
DEFINE-VOP, DEFINE-MOVE-VOP defining macros [and friends] in
the CMUCL compiler. They provide a domain-specific language for
describing virtual instruction sets. From a comment in the source:

  ;;;; VOP definition structures:
  ;;;
  ;;; Define-VOP uses some fairly complex data structures at meta-compile
  ;;; time, both to hold the results of parsing the elaborate syntax and
  ;;; to retain the information so that it can be inherited by other VOPs.

  ;;; The VOP-Parse structure holds everything we need to know about a VOP
  ;;; at meta-compile time.
  ;;;

CMUCL thus has its own little [or *not* so little!] compiler-compiler
inside itself.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Barry Margolin
Subject: Re: A "killer" macro
Date: 
Message-ID: <barmar-16ED63.21262012092007@comcast.dca.giganews.com>
In article <···················@newsfe12.lga>,
 Ken Tilton <···········@optonline.net> wrote:

> Christophe wrote:
> > On 12 sep, 08:59, Eli Bendersky <······@gmail.com> wrote:
> > 
> >>Hello all,
> >>
> >>In short: I'm looking for a "killer" macro - a macro (or a couple of
> >>related ones) that show what Lisp can do and other languages (those
> >>without uniform syntax) can not.
> 
> ....
> 
> > No needs to search a long time : loop, iterate or defclass are smart
> > examples.
> 
> You are absolutely right, but others will say, "Hunh? Those are part of 
> the language. You think implementing classes in C++ is easy?"

LOOP was not originally part of the language, it was a user-written 
macro in MacLISP.  And even though it's now part of the standard, it's 
still implemented pretty much the same way (I'll bet that at least 75% 
of the code in most LOOP implementations is from the original MIT LOOP).

And ITERATE is not a part of the language.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Ken Tilton
Subject: Re: A "killer" macro
Date: 
Message-ID: <823Gi.1679$Z%7.1218@newsfe12.lga>
Barry Margolin wrote:
> In article <···················@newsfe12.lga>,
>  Ken Tilton <···········@optonline.net> wrote:
> 
> 
>>Christophe wrote:
>>
>>>On 12 sep, 08:59, Eli Bendersky <······@gmail.com> wrote:
>>>
>>>
>>>>Hello all,
>>>>
>>>>In short: I'm looking for a "killer" macro - a macro (or a couple of
>>>>related ones) that show what Lisp can do and other languages (those
>>>>without uniform syntax) can not.
>>
>>....
>>
>>
>>>No needs to search a long time : loop, iterate or defclass are smart
>>>examples.
>>
>>You are absolutely right, but others will say, "Hunh? Those are part of 
>>the language. You think implementing classes in C++ is easy?"
> 
> 
> LOOP was not originally part of the language, it was a user-written 
> macro in MacLISP.  And even though it's now part of the standard, it's 
> still implemented pretty much the same way (I'll bet that at least 75% 
> of the code in most LOOP implementations is from the original MIT LOOP).
> 
> And ITERATE is not a part of the language.
> 

Deftly missing my entire point, thus nicely reinforcing my point that 
even lucid points have little chance against minds that already know 
what they are reading before they read it.

kt

-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: Rayiner Hashem
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189634559.591454.16590@d55g2000hsg.googlegroups.com>
> What is needed is an example of where an application code pattern can be
> automated, and natch it has to be one where a function would not do.
>
> kt

Alexanderscu's "Modern C++ Design" is basically exactly about this:
implementing "patterns" (in the Gang of Four sense) in code. Except he
uses a weak "macro" language to express these solutions. You could go
through the book and pick out few and show how they are much easier to
express with Lisp macros.
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189673129.438733.39260@y42g2000hsy.googlegroups.com>
> Alexanderscu's "Modern C++ Design" is basically exactly about this:
> implementing "patterns" (in the Gang of Four sense) in code. Except he
> uses a weak "macro" language to express these solutions. You could go
> through the book and pick out few and show how they are much easier to
> express with Lisp macros.

"Modern C++ Design" is a piece of monstrosity. It's what turned me
away from C++, actually. I just kept reading it and thinking - "my
god, should this really be so hard ? should I really use all these
ugly tricks to fool the compiler in order to write normal code ?"

That said, maybe reimplementing the horrors of Modern C++ Design in
CL  is a good idea.
From: ··············@yahoo.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189690372.018374.303390@k79g2000hse.googlegroups.com>
> "Modern C++ Design" is a piece of monstrosity. It's what turned me
> away from C++, actually.

What turned me away was sitting with a Stroustroup C++ book in hand,
staring at the STL examples for hours, trying to get a simple iterator
to iterate over a damn container class.  A day later, when I finally
had the syntax correct, the iterator scrolled off the screen
(something like <std::blah::blah>>blah.blah.blah...), and worse I had
to cut and paste the damn thing every time I wanted to use it.  Then I
glanced over at Smalltalk where I saw a simple "x do:[whatever]" to
iterate over a collection, said "screw this" and threw the C++ book
across the room, and never looked back.  This, by the way, is coming
from someone who once wrote a C compiler for a project in college.

<<That said, maybe reimplementing the horrors of Modern C++ Design in
CL  is a good idea. >>

Please... no... I beg you....
From: Jeronimo Pellegrini
Subject: Re: A "killer" macro
Date: 
Message-ID: <fcbgs9$hbg$1@aioe.org>
On 2007-09-13, ··············@yahoo.com <··············@yahoo.com> wrote:
>> "Modern C++ Design" is a piece of monstrosity. It's what turned me
>> away from C++, actually.
>
> What turned me away was sitting with a Stroustroup C++ book in hand,
> staring at the STL examples for hours, trying to get a simple iterator
> to iterate over a damn container class.  A day later, when I finally
> had the syntax correct, the iterator scrolled off the screen
> (something like <std::blah::blah>>blah.blah.blah...), and worse I had
> to cut and paste the damn thing every time I wanted to use it.  Then I
> glanced over at Smalltalk where I saw a simple "x do:[whatever]" to
> iterate over a collection, said "screw this" and threw the C++ book
> across the room, and never looked back.  This, by the way, is coming
> from someone who once wrote a C compiler for a project in college.

I have been trying to move away from C++ for other reasons, and I don't
like C++, but iterating is not supposed to be hard:

#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
...
	std::vector<some-type> v;
	...
	foreach(some-type element, v) {
		...
	}
	some-type el;
	foreach(el, v) {
		...
	}

Works for anything that supports iterators.

My problem with C++ is on other areas...
It's hard to debug, build systems are a pain (it's not interactive), the
exception mechanism is not good, metaprogramming is insane (you can use
macros like boost's foreach easily, but trying to create your own macros
as you do in Lisp will drive you nuts), and other languages seem to allow
for cleaner code.

J.
From: Thomas A. Russ
Subject: Re: A "killer" macro
Date: 
Message-ID: <ymid4wma5z0.fsf@blackcat.isi.edu>
Jeronimo Pellegrini <···@aleph0.info> writes:

> On 2007-09-13, ··············@yahoo.com <··············@yahoo.com> wrote:
> 
> I have been trying to move away from C++ for other reasons, and I don't
> like C++, but iterating is not supposed to be hard:
> 
> #include <boost/foreach.hpp>
> #define foreach BOOST_FOREACH
> ...
> 	std::vector<some-type> v;
> 	...
> 	foreach(some-type element, v) {
> 		...
> 	}
> 	some-type el;
> 	foreach(el, v) {
> 		...
> 	}
> 
> Works for anything that supports iterators.

Ah, but what does the implementation of BOOST_FOREACH look like,
compared to the Lisp equivalent?  Would it be something that would be
easy for most C++ programmers to produce?

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Rayiner Hashem
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189714886.243991.273410@w3g2000hsg.googlegroups.com>
> Ah, but what does the implementation of BOOST_FOREACH look like,
> compared to the Lisp equivalent?  Would it be something that would be
> easy for most C++ programmers to produce?

Boost is a mix of C++ preprocessor code and template magic. As far as
I'm concerned, it's write-only code. In fact, almost every non-trivial
use of templates or the STL is very ugly on the library side. Eg:
extending Iterate to handle a new container is maybe a dozen lines of
code, while writing custom iterators for the STL involves a couple of
pages of code. Heck, I'd be quite surprised if anybody can write an
STL iterator from memory, without having to refer repeatedly to a
reference or some example code.

Ultimately, though, Boost, the STL, "Modern C++" is rooted in some
good ideas. It's good to have a generic iteration facility, to define
syntactic extensions to the language, to encapsulate design patterns
into meta-code. Lispers take these ideas for granted, but they were
basically unknown to C++ until Alexanderscu's book and the stuff that
followed it packaged the ideas into an appropriately well-hyped form.
From: Jeronimo Pellegrini
Subject: Re: A "killer" macro
Date: 
Message-ID: <fcc6o8$fg2$1@aioe.org>
On 2007-09-13, Thomas A. Russ <···@sevak.isi.edu> wrote:
> Ah, but what does the implementation of BOOST_FOREACH look like,
> compared to the Lisp equivalent?  Would it be something that would be
> easy for most C++ programmers to produce?

That's why I said it's easy to use C++ macros, but writing one would
drive you nuts... :-)

But I don't think the problem with C++ is that it's hard to iterate over
STL containers (it's simple with boost::foreach). There are other, more
fundamental problems with the language.

J.
From: ··············@yahoo.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189777642.682553.62430@57g2000hsv.googlegroups.com>
> > Works for anything that supports iterators.
>
> Ah, but what does the implementation of BOOST_FOREACH look like,
> compared to the Lisp equivalent?  Would it be something that would be
> easy for most C++ programmers to produce?

I couldn't get anything like what this poster posted for a C++
iterator to work.  My simple problem required something far more
monstrous and ugly.
From: ····@tidexsystems.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189686060.042064.98470@g4g2000hsf.googlegroups.com>
Eli Bendersky <······@gmail.com> writes:

>> Alexanderscu's "Modern C++ Design" is basically exactly about this:
>> implementing "patterns" (in the Gang of Four sense) in code. Except he
>> uses a weak "macro" language to express these solutions. You could go
>> through the book and pick out few and show how they are much easier to
>> express with Lisp macros.
>
> "Modern C++ Design" is a piece of monstrosity. It's what turned me
> away from C++, actually. I just kept reading it and thinking - "my
> god, should this really be so hard ? should I really use all these
> ugly tricks to fool the compiler in order to write normal code ?"
>
> That said, maybe reimplementing the horrors of Modern C++ Design in
> CL  is a good idea.

Speaking of Alexandrescu, it's worth mentioning that he is also the
author of ScopeGuard, a well-known C++ library that makes writing
exception-safe code easier.

Some time ago, ScopeGuard was discussed on c.l.c++.m.  Alexandrescu
says about ScopeGuard (Message-ID <IrEDKt.
···@beaver.cs.washington.edu>):

>  ScopeGuard is a kludge invented in absence of on_scope_xxx. We've even
>  written a macro, ON_BLOCK_EXIT, that awkwardly emulates on_scope_exit.
>  ScopeGuard is limited and awkward because it lacks access to the current
>  scope; often you need to stop doing what you're doing just to write some
>  little function that doesn't help anywhere else.

In another post, he says (Message-ID
<··········@beaver.cs.washington.edu>):

>  Again, ScopeGuard is a lame paliative for the highly desirable
>  on_scope_xxx feature. Its usefulness comes from us needing and lacking
>  the true on_scope_xxx feature.

A few posts later, Common Lisp's unwind-protect operator is mentioned.
According to Alexandrescu, the problem with unwind-protect, and with
any nested structure for an on_scope_xxx construct that includes
normal code within it, is that it doesn't scale.  (Message-ID
<··········@beaver.cs.washington.edu>)

Alexandrescu would like something like the following to work:

  (defun hello-world ()
    "Hello, world."
    (on-exit (format t "exiting...~%"))
    (guard foo (format t "guard...~%"))
    (unless (y-or-n-p "run guard")
      (dismiss foo))
    (format t "hello, world~%"))

On-exit is supposed to queue the form(s) to run on scope exit; guard
is supposed to do the same, but also give the form(s) a name so that
they can be selectively dismissed.  In-scope (use not shown here)
establishes a scope, and defun should implicitly establish such a
scope, too.

This feature is easily implemented with macros (note that defun is
shadowed):

(defmacro in-scope (&body body)
  (let ((guards (gensym "GUARDS-")))
    `(let ((,guards '()))
       (unwind-protect
            (macrolet ((guard (name &body body)
                         `(push (cons ',name (lambda
() ,@body)) ,',guards))
                       (dismiss (name)
                         `(setf ,',guards
                                (delete ',name ,',guards :key #'car)))
                       (on-exit (&body body)
                         `(push (cons '#:anon (lambda
() ,@body)) ,',guards)))
              ,@body)
         (dolist (guard ,guards)
           (funcall (cdr guard)))))))

(defmacro defun (name lambda-list &body body)
  `(cl:defun ,name ,lambda-list
      ,@(if (stringp (car body)) (list (car body)) '())
      (in-scope ,@(if (stringp (car body)) (cdr body) body))))

How would non-Lispers handle this?

Ariel
From: Dimiter "malkia" Stanev
Subject: Re: A "killer" macro
Date: 
Message-ID: <5ktpihF5cofkU2@mid.individual.net>
Another cool macro! Thanks!

····@tidexsystems.com wrote:
> Eli Bendersky <······@gmail.com> writes:
> 
>>> Alexanderscu's "Modern C++ Design" is basically exactly about this:
>>> implementing "patterns" (in the Gang of Four sense) in code. Except he
>>> uses a weak "macro" language to express these solutions. You could go
>>> through the book and pick out few and show how they are much easier to
>>> express with Lisp macros.
>> "Modern C++ Design" is a piece of monstrosity. It's what turned me
>> away from C++, actually. I just kept reading it and thinking - "my
>> god, should this really be so hard ? should I really use all these
>> ugly tricks to fool the compiler in order to write normal code ?"
>>
>> That said, maybe reimplementing the horrors of Modern C++ Design in
>> CL  is a good idea.
> 
> Speaking of Alexandrescu, it's worth mentioning that he is also the
> author of ScopeGuard, a well-known C++ library that makes writing
> exception-safe code easier.
> 
> Some time ago, ScopeGuard was discussed on c.l.c++.m.  Alexandrescu
> says about ScopeGuard (Message-ID <IrEDKt.
> ···@beaver.cs.washington.edu>):
> 
>>  ScopeGuard is a kludge invented in absence of on_scope_xxx. We've even
>>  written a macro, ON_BLOCK_EXIT, that awkwardly emulates on_scope_exit.
>>  ScopeGuard is limited and awkward because it lacks access to the current
>>  scope; often you need to stop doing what you're doing just to write some
>>  little function that doesn't help anywhere else.
> 
> In another post, he says (Message-ID
> <··········@beaver.cs.washington.edu>):
> 
>>  Again, ScopeGuard is a lame paliative for the highly desirable
>>  on_scope_xxx feature. Its usefulness comes from us needing and lacking
>>  the true on_scope_xxx feature.
> 
> A few posts later, Common Lisp's unwind-protect operator is mentioned.
> According to Alexandrescu, the problem with unwind-protect, and with
> any nested structure for an on_scope_xxx construct that includes
> normal code within it, is that it doesn't scale.  (Message-ID
> <··········@beaver.cs.washington.edu>)
> 
> Alexandrescu would like something like the following to work:
> 
>   (defun hello-world ()
>     "Hello, world."
>     (on-exit (format t "exiting...~%"))
>     (guard foo (format t "guard...~%"))
>     (unless (y-or-n-p "run guard")
>       (dismiss foo))
>     (format t "hello, world~%"))
> 
> On-exit is supposed to queue the form(s) to run on scope exit; guard
> is supposed to do the same, but also give the form(s) a name so that
> they can be selectively dismissed.  In-scope (use not shown here)
> establishes a scope, and defun should implicitly establish such a
> scope, too.
> 
> This feature is easily implemented with macros (note that defun is
> shadowed):
> 
> (defmacro in-scope (&body body)
>   (let ((guards (gensym "GUARDS-")))
>     `(let ((,guards '()))
>        (unwind-protect
>             (macrolet ((guard (name &body body)
>                          `(push (cons ',name (lambda
> () ,@body)) ,',guards))
>                        (dismiss (name)
>                          `(setf ,',guards
>                                 (delete ',name ,',guards :key #'car)))
>                        (on-exit (&body body)
>                          `(push (cons '#:anon (lambda
> () ,@body)) ,',guards)))
>               ,@body)
>          (dolist (guard ,guards)
>            (funcall (cdr guard)))))))
> 
> (defmacro defun (name lambda-list &body body)
>   `(cl:defun ,name ,lambda-list
>       ,@(if (stringp (car body)) (list (car body)) '())
>       (in-scope ,@(if (stringp (car body)) (cdr body) body))))
> 
> How would non-Lispers handle this?
> 
> Ariel
> 
From: Nicolas Neuss
Subject: Re: A "killer" macro
Date: 
Message-ID: <87r6l42l6h.fsf@ma-patru.mathematik.uni-karlsruhe.de>
Christophe <····················@birdtechnology.net> writes:

> On 12 sep, 08:59, Eli Bendersky <······@gmail.com> wrote:
> > Hello all,
> >
> > In short: I'm looking for a "killer" macro - a macro (or a couple of
> > related ones) that show what Lisp can do and other languages (those
> > without uniform syntax) can not.
> >
> > A longer version: Many contemporary languages boast their sharing most
> > of the functional features of Lisp. Perl, Ruby, Javascript - all have
> > convenient lists (or arrays), functions as first class objects,
> > garbage collection, dynamic typing, lexical closures. However, one
> > thing they lack is uniform syntax, and hence the service of a powerful
> > built-in macro system such as Common Lisp's "defmacro".
> > When confronted by fellow programmers with the question "so why is
> > Lisp so special", I'm looking for that short - not too hard to
> > understand - snippet of code that will show them *why*. I'm convinced
> > that such a snippet must involve macros. But all the examples I ran
> > into so far have been either too simple - and could be easily
> > implemented another way (for example with Ruby's blocks), or too
> > complicated.
> >
> > Any suggestions for such an example ?
> >
> > Eli
> 
> Hello,
> 
> Quickly, Macro in Lisp is, in fact, a way to create your own domain
> specific language.
> 
> No needs to search a long time : loop, iterate or defclass are smart
> examples.

Seconded.  The point is that a CL programmer can be pretty sure that he can
adapt CL to any new programming paradigm without hacking the CL
implementation, whereas in other languages this is often impossible.  Tell
them to implement a full CLOS-equivalent (dynamic class changes, multiple
inheritance, multimethods) in their respective language.  Then tell them
that this was possible in pre-CL-Lisp.

Nicolas
From: Aurélien Campéas
Subject: Re: A "killer" macro
Date: 
Message-ID: <46ead3a1$0$21558$426a34cc@news.free.fr>
Nicolas Neuss wrote:
> Christophe <····················@birdtechnology.net> writes:
> 
>> On 12 sep, 08:59, Eli Bendersky <······@gmail.com> wrote:
>>> Hello all,
>>>
>>> In short: I'm looking for a "killer" macro - a macro (or a couple of
>>> related ones) that show what Lisp can do and other languages (those
>>> without uniform syntax) can not.
>>>
>>> A longer version: Many contemporary languages boast their sharing most
>>> of the functional features of Lisp. Perl, Ruby, Javascript - all have
>>> convenient lists (or arrays), functions as first class objects,
>>> garbage collection, dynamic typing, lexical closures. However, one
>>> thing they lack is uniform syntax, and hence the service of a powerful
>>> built-in macro system such as Common Lisp's "defmacro".
>>> When confronted by fellow programmers with the question "so why is
>>> Lisp so special", I'm looking for that short - not too hard to
>>> understand - snippet of code that will show them *why*. I'm convinced
>>> that such a snippet must involve macros. But all the examples I ran
>>> into so far have been either too simple - and could be easily
>>> implemented another way (for example with Ruby's blocks), or too
>>> complicated.
>>>
>>> Any suggestions for such an example ?
>>>
>>> Eli
>> Hello,
>>
>> Quickly, Macro in Lisp is, in fact, a way to create your own domain
>> specific language.
>>
>> No needs to search a long time : loop, iterate or defclass are smart
>> examples.

Unsure. Ruby, Python et al all have their idiomatic ways to loop/iterate 
and the CL loop/iterate packages might just look like a big WTF to users 
of these languages.

> 
> Seconded.  The point is that a CL programmer can be pretty sure that he can
> adapt CL to any new programming paradigm without hacking the CL
> implementation, whereas in other languages this is often impossible.  Tell
> them to implement a full CLOS-equivalent (dynamic class changes, multiple
> inheritance, multimethods) in their respective language.  Then tell them
> that this was possible in pre-CL-Lisp.

Something quite CLOSish is available for Python (and might get included 
in python 3) : http://www.python.org/dev/peps/pep-3124/, that is 
implemented 100% in python (ie without C level hacks). Note that python 
already has multiple inheritance ; not sure how that might be done in 
pure python.

Anyway [to the OP], you would have to convince your fellow programmer 
that CLOS is something they might want to have. Which is by the way 
(imho) a better selling point for CL than macros.

Aur�lien.
From: ·············@gmail.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189593999.122722.129870@o80g2000hse.googlegroups.com>
I think SETF facility is the best example. You can build your own
magic on top of it (like ! macro from "On Lisp"). E.g. some other
languages have concept of reference, but few support generic places.
This is something them I'm missing in other languages (except C++
where it's possible to do similar things with it's templates black
magic).
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kq52mF4p4dkU2@mid.individual.net>
·············@gmail.com wrote:
> I think SETF facility is the best example. You can build your own
> magic on top of it (like ! macro from "On Lisp"). E.g. some other
> languages have concept of reference, but few support generic places.
> This is something them I'm missing in other languages (except C++
> where it's possible to do similar things with it's templates black
> magic).

Same problem as with my while macro - or probably even worse. Many 
people don't see why (setf (car cons) 345) is better than (set-car! cons 
345).

I think my while macro is more convincing because it hides away an 
aspect of the implementation (the fact that lambdas are used in a 
functional version) that you cannot hide away otherwise.

With setf nothing is hidden away. It's "just" nicer.


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: Barry Margolin
Subject: Re: A "killer" macro
Date: 
Message-ID: <barmar-22B48F.21332012092007@comcast.dca.giganews.com>
In article <··············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> ·············@gmail.com wrote:
> > I think SETF facility is the best example. You can build your own
> > magic on top of it (like ! macro from "On Lisp"). E.g. some other
> > languages have concept of reference, but few support generic places.
> > This is something them I'm missing in other languages (except C++
> > where it's possible to do similar things with it's templates black
> > magic).
> 
> Same problem as with my while macro - or probably even worse. Many 
> people don't see why (setf (car cons) 345) is better than (set-car! cons 
> 345).

Yet they probably have little problem understanding why conventional 
languages use the same assignment syntax for everything:

var = val;
array[subscript] = val;
struct.member = val;

They would presumably consider it cumbersome to have to write:

array_assign(array, subscript, val);

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kv5usF5jsceU2@mid.individual.net>
Barry Margolin wrote:
> In article <··············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
>> ·············@gmail.com wrote:
>>> I think SETF facility is the best example. You can build your own
>>> magic on top of it (like ! macro from "On Lisp"). E.g. some other
>>> languages have concept of reference, but few support generic places.
>>> This is something them I'm missing in other languages (except C++
>>> where it's possible to do similar things with it's templates black
>>> magic).
>> Same problem as with my while macro - or probably even worse. Many 
>> people don't see why (setf (car cons) 345) is better than (set-car! cons 
>> 345).
> 
> Yet they probably have little problem understanding why conventional 
> languages use the same assignment syntax for everything:
> 
> var = val;
> array[subscript] = val;
> struct.member = val;
> 
> They would presumably consider it cumbersome to have to write:
> 
> array_assign(array, subscript, val);

Yes, this is also a complete mystery to me. Even if you put the 
equivalent code using Common Lisp's setf and the other language's 
assignment operator side by side, they don't seem to get it.

That's weird, I don't have a good explanation for that.


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: Barry Margolin
Subject: Re: A "killer" macro
Date: 
Message-ID: <barmar-4F1171.20584614092007@comcast.dca.giganews.com>
In article <··············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Barry Margolin wrote:
> > In article <··············@mid.individual.net>,
> >  Pascal Costanza <··@p-cos.net> wrote:
> > 
> >> ·············@gmail.com wrote:
> >>> I think SETF facility is the best example. You can build your own
> >>> magic on top of it (like ! macro from "On Lisp"). E.g. some other
> >>> languages have concept of reference, but few support generic places.
> >>> This is something them I'm missing in other languages (except C++
> >>> where it's possible to do similar things with it's templates black
> >>> magic).
> >> Same problem as with my while macro - or probably even worse. Many 
> >> people don't see why (setf (car cons) 345) is better than (set-car! cons 
> >> 345).
> > 
> > Yet they probably have little problem understanding why conventional 
> > languages use the same assignment syntax for everything:
> > 
> > var = val;
> > array[subscript] = val;
> > struct.member = val;
> > 
> > They would presumably consider it cumbersome to have to write:
> > 
> > array_assign(array, subscript, val);
> 
> Yes, this is also a complete mystery to me. Even if you put the 
> equivalent code using Common Lisp's setf and the other language's 
> assignment operator side by side, they don't seem to get it.
> 
> That's weird, I don't have a good explanation for that.

I think it's because convention languages use "syntax" for assignment, 
while everything in Lisp looks like a fuction call.  They're used to the 
idea that special syntax allows for context-dependent behavior, but less 
so for function-like things.  Although you'd think that people using 
languages with function overloading (e.g. C++) wouldn't find it so 
strange.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kpm9gF4s7siU1@mid.individual.net>
Eli Bendersky wrote:
> Hello all,
> 
> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.
> 
> A longer version: Many contemporary languages boast their sharing most
> of the functional features of Lisp. Perl, Ruby, Javascript - all have
> convenient lists (or arrays), functions as first class objects,
> garbage collection, dynamic typing, lexical closures. However, one
> thing they lack is uniform syntax, and hence the service of a powerful
> built-in macro system such as Common Lisp's "defmacro".
> When confronted by fellow programmers with the question "so why is
> Lisp so special", I'm looking for that short - not too hard to
> understand - snippet of code that will show them *why*. I'm convinced
> that such a snippet must involve macros. But all the examples I ran
> into so far have been either too simple - and could be easily
> implemented another way (for example with Ruby's blocks), or too
> complicated.
> 
> Any suggestions for such an example ?

Here is my best attempt so far: 
http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html


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: Thomas F. Burdick
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189590672.502993.102630@57g2000hsv.googlegroups.com>
On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
> Eli Bendersky wrote:
>
> > I'm looking for that short - not too hard to
> > understand - snippet of code that will show them *why*. I'm convinced
> > that such a snippet must involve macros. But all the examples I ran
> > into so far have been either too simple - and could be easily
> > implemented another way (for example with Ruby's blocks), or too
> > complicated.
>
> > Any suggestions for such an example ?
>
> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html

The problem with this example is that, while it does demonstrate that
macros are structural transforms of the code itself, it doesn't do
anything that can't also be done in languages with light-weight
lambdas.  Eg, if you were to look at Smalltalk code written by me,
you'll notice things like:

  outfile withOutputStream: [:out |
    infile doInputLines:
      [:line | out nextLinePut: line]]

withOutputStream abstracting away the need for ensure: (ie, unwind-
protect), and doInputLines: abstracting away that plus the loop of
reading line-by-line while input is available.  While abstracting away
the lambdas is a win for Lisp, that's not universal, so at least a
doubtful ST'er won't see anything there.
From: Rainer Joswig
Subject: Re: A "killer" macro
Date: 
Message-ID: <joswig-C7B9BF.12382912092007@news-europe.giganews.com>
In article <························@57g2000hsv.googlegroups.com>,
 "Thomas F. Burdick" <········@gmail.com> wrote:

> On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
> > Eli Bendersky wrote:
> >
> > > I'm looking for that short - not too hard to
> > > understand - snippet of code that will show them *why*. I'm convinced
> > > that such a snippet must involve macros. But all the examples I ran
> > > into so far have been either too simple - and could be easily
> > > implemented another way (for example with Ruby's blocks), or too
> > > complicated.
> >
> > > Any suggestions for such an example ?
> >
> > Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
> 
> The problem with this example is that, while it does demonstrate that
> macros are structural transforms of the code itself, it doesn't do
> anything that can't also be done in languages with light-weight
> lambdas.  Eg, if you were to look at Smalltalk code written by me,
> you'll notice things like:
> 
>   outfile withOutputStream: [:out |
>     infile doInputLines:
>       [:line | out nextLinePut: line]]
> 
> withOutputStream abstracting away the need for ensure: (ie, unwind-
> protect), and doInputLines: abstracting away that plus the loop of
> reading line-by-line while input is available.  While abstracting away
> the lambdas is a win for Lisp, that's not universal, so at least a
> doubtful ST'er won't see anything there.

I also can't see why

(with-input-file (in filename)
  (do-something in))

is better than

(call-with-input-file filename do-something)

In the case of a &body we have:

(call-with-input-file filename
  (lambda (in)
    ...))

With a readmacro we could have:

(call-with-input-file filename [in |
  ...]) 


But then what with parameters?


(with-input-file (in filename :element-type '(unsigned-byte 0))
  (do-something in))

What now with CALL-WITH-INPUT-FILE?

(call-with-input-file filename do-something :element-type '(unsigned-byte 0))

  Extensible, more keyword parameters can added to the end. Unfortunately
  they are to behind the function parameter

or

(call-with-input-file filename do-something '(:element-type (unsigned-byte 0)))

  Take all parameters and convert them into a list. Usually not CL style for
  basic function interfaces.

or

(call-with-input-file filename '(:element-type (unsigned-byte 0)) do-something)

  As above, but we can move the additional parameters before the function
  parameter. Gets easier to read with long code. See below. Still not
  CL argument list style.


Then

(call-with-input-file filename
  (lambda (in)
    ...)
  :element-type '(unsigned-byte 0))

   Makes reading harder when you have larger code. Options should be above
   the function in the text.
   

or

(call-with-input-file filename
  (lambda (in)
    ...)
  '(:element-type (unsigned-byte 0)))

or

(call-with-input-file filename
  '(:element-type (unsigned-byte 0))
  (lambda (in)
    ...))
 
  To move the options to the front we need to make them a list.
  Something like (foo arg :bar1 a1 :bar2 a2 ... :barn an fn) is not a good
  arglist in CL.
  

So, the macro allows you to group the parameters better. New args can be added easily,
the args don't need to be listified and the code body comes last.

(with-input-file (in filename :element-type '(unsigned-byte 0))
  (do-something in))

-- 
http://lispm.dyndns.org
From: Kent M Pitman
Subject: Re: A "killer" macro
Date: 
Message-ID: <u642g2d8k.fsf@nhplace.com>
Rainer Joswig <······@lisp.de> writes:

> I also can't see why
> 
> (with-input-file (in filename)
>   (do-something in))
> 
> is better than
> 
> (call-with-input-file filename do-something)

1. Because of indentation issues.  The former makes more textually
   appropriate use of visual space.

2. Because of aesthetic issues that amount to a religious divide and that 
   may or may not appeal to you, but that are real to many.  In the history
   of mathematics, there was a longstanding confusion about the difference
   between a function and an expression, owing in part to notations like 

   /
   |  x^2 dx
   /

   or if you prefer Lisp notation:

   (integral (^ x 2) x)

   rather than:

   int(f) where { f(x) = x^2 }

   There are some people who think that the change was a big improvement
   and others who find it cumbersome to think of integrals this way.  See
   my 1980 paper on macros 
   ( http://www.nhplace.com/kent/Papers/Special-Forms.html )
   for the issues surrounding why people write macros and yet why it's useful
   to be able to get at the functional form.  I think both are important.

   I used to program in a world, around 1978 when I arrived to Lisp, where
   LET was a macro users had to write and we wrote everything as 
   ((lambda (x) ...) binding-for-x)
   The problem was that it made things execute backwards [first the binding
   then the body, which was textually to the left or above].  Macros give
   you control of that, too (especially important if your language is not 
   lazy).

3. A logical extension of your argument is to suggest that IF has no purpose
   as a macro, and people should write a function:
    (*if test (lambda () consequent) (lambda () alternative))
   If you don't see that some of this is just syntactic baggage, you won't
   get this argument.  Making a lambda just to consume it is like the user
   doing the system's job.  And that's how people feel about 
   (call-with-input-file filename do-something)
   when the do-something is
   (call-with-input-file filename (lambda (stream) ...))
   Every word there has a purpose except the lambda, which is just going to
   get opened back into a function body instantly, and which in the meantime
   is only further increasing indentation, and doing so EVEN IF you move it
   to a new line, since it costs you three lines to get even close to where
   the other would have done
   (call-with-input-file filename
     (lambda (stream) 
       ...))
   And even then if you want to give "options" you can't see them at the start
   where you are going to need to if reading top-to-bottom/left-to-right, 
   you'll see them at the end, out of order from the evaluation order.

I am NOT trying to say that you should believe these arguments, but can you
see how some of these things would matter to others?
From: Rainer Joswig
Subject: Re: A "killer" macro
Date: 
Message-ID: <joswig-284C9C.16290012092007@news-europe.giganews.com>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> Rainer Joswig <······@lisp.de> writes:
> 
> > I also can't see why
> > 
> > (with-input-file (in filename)
> >   (do-something in))
> > 
> > is better than
> > 
> > (call-with-input-file filename do-something)
> 
> 1. Because of indentation issues.  The former makes more textually
>    appropriate use of visual space.

But that could be fixed with a indentation rule.

> 
> 2. Because of aesthetic issues that amount to a religious divide and that 
>    may or may not appeal to you, but that are real to many.  In the history
>    of mathematics, there was a longstanding confusion about the difference
>    between a function and an expression, owing in part to notations like 

I agree with 2.

I also think that not everything should be expressed in functional terms
and also that not every macro should expand into a functional expression.
If WHILE has a more primitive expansion, I'm happy with it.

> 3. A logical extension of your argument is to suggest that IF has no purpose
>    as a macro, and people should write a function:
>     (*if test (lambda () consequent) (lambda () alternative))
>    If you don't see that some of this is just syntactic baggage, you won't
>    get this argument.  Making a lambda just to consume it is like the user
>    doing the system's job.  And that's how people feel about 
>    (call-with-input-file filename do-something)
>    when the do-something is
>    (call-with-input-file filename (lambda (stream) ...))
>    Every word there has a purpose except the lambda, which is just going to
>    get opened back into a function body instantly, and which in the meantime
>    is only further increasing indentation, and doing so EVEN IF you move it
>    to a new line, since it costs you three lines to get even close to where
>    the other would have done
>    (call-with-input-file filename
>      (lambda (stream) 
>        ...))
>    And even then if you want to give "options" you can't see them at the start
>    where you are going to need to if reading top-to-bottom/left-to-right, 
>    you'll see them at the end, out of order from the evaluation order.

Somehow I wouldn't put things like IF, WHILE, LOOP, CATCH etc.
into the same category as CALL-WITH-OPEN-FILE. I see the latter
as a higher-order'task'. One I also want to see on the stack. Directly. With
useful parameters. I could for example extract the DO-SOMETHING
function in a debugger and apply it to something. WITH-OPEN-FILE
is invisible on the stack. It creates some weird code that
has no simple representation. Worse. it might be completely replaced
with a bunch of new things I would never associate with WITH-OPEN-FILE.
When I want to edit source for the stack frame, it somehow has to figure
out that there was some macro call and find it. WITH-OPEN-FILE also can't be composed
with other functions. I feel it is just in the way. In the
source code it might look useful. But the one-2-one correspondence
of source and what I see on the stack is gone. I'm willing to
give that up for IF, WHILE, LOOP and others - but somehow not
for CALL-WITH-OPEN-FILE.

> 
> I am NOT trying to say that you should believe these arguments, but can you
> see how some of these things would matter to others?

Sure.

-- 
http://lispm.dyndns.org
From: Kent M Pitman
Subject: Re: A "killer" macro
Date: 
Message-ID: <ufy1jct9j.fsf@nhplace.com>
Rainer Joswig <······@lisp.de> writes:

> In article <·············@nhplace.com>,
>  Kent M Pitman <······@nhplace.com> wrote:
> 
> > Rainer Joswig <······@lisp.de> writes:
> > 
> > > I also can't see why
> > > 
> > > (with-input-file (in filename)
> > >   (do-something in))
> > > 
> > > is better than
> > > 
> > > (call-with-input-file filename do-something)
> > 
> > 1. Because of indentation issues.  The former makes more textually
> >    appropriate use of visual space.
> 
> But that could be fixed with a indentation rule.

Ick. I hate for functions to be indented like macros.  I use the presence
of non-standard indentation to alert me to the non-standard evaluation rules.

So count that as "no" for me, even though I perfectly well understand
that you might want to take such an approach.  As I said, and as I'm
pretty sure you correctly understand already, the intent of my remarks
wasn't to "convince you", it was to "explain me".

I admit to being surprised that you find this indentation fix aesthetic,
since I only ever do such things in outright desperation for screen space, 
but I'm glad you mentioned it and I accept that you might differ on this.

> > 3. A logical extension of your argument is to suggest that IF has no purpose
> >    as a macro, and people should write a function:
> >     (*if test (lambda () consequent) (lambda () alternative))
>
> Somehow I wouldn't put things like IF, WHILE, LOOP, CATCH etc.
> into the same category as CALL-WITH-OPEN-FILE. I see the latter
> as a higher-order'task'.

Well, in the context of CL, the underlying function is OPEN, and it's
already available as a function.  You're right that this could be done
as a function, but historically it did not arise that way.

Before WITH-OPEN-FILE, I used to just use a LET with an OPEN, and I
remember someone getting really mad at me one day on the PDP-10
running the ITS operating system, which had only a finite number of
file channels.  I'd used them all up, not realizing it, because the
bindings were gone but the GC had not run (which would have closed
them).  I asked what to do and no one had a good answer.  Soon after,
there was an UNWIND-PROTECT added to the language, and I wrote a macro
called IOTA (trying to make it greek so it would sound like LAMBDA, a
binding form, but also like "I/O"). It allowed multiple binding forms,
so it was easy to rewrite a LET into it.  I think that's how we
started down the path to having it be a macro.  IOTA became widely
used in MACLISP, at least at the MIT Lab for Computer Science--I don't
know if it got distributed.  We weren't very formal about these things.
[On another day, ask me about PI, the macro I wrote for binding...
you guessed it... program interrupts.  It was later renamed to 
WITHOUT-INTERRUPTS.]

Incidentally, too, back to CL, you should know that when I write these
WITH-xxx macros, I almost always accompany them with a CALL-WITH-xxx
so that I can do either kind of call.  But I find I almost never use
the CALL-WITH-xxx even when I was the one to provide it as an option.
The main reason I write them is not to use them but to make
redefinition easier, since I can redefine the CALL-WITH-xxx without
redefining the macro, and so I don't have to recompile the callers if
the definition changes.

> One I also want to see on the stack. Directly. With
> useful parameters. I could for example extract the DO-SOMETHING
> function in a debugger and apply it to something. WITH-OPEN-FILE
> is invisible on the stack.

Well, not the way I generally do it, so I mostly don't see this deficiency.
(Note: I didn't say "I don't see this AS a deficiency", I mean it really
isn't one because we (you and I) both see the same thing on the stack,
since my macro call often expands into the function call that you wrote
explicitly, and so at the time of looking on the stack, the textual pedigree
of the call is long-since erased and the two techniques are blurred by
a common functional implementation.)

Put another way, I often start with the implementation of the function you like
and THEN write the macro because I hate its syntax.  You seem to be assuming
I'm starting with a blank sheet and first writing a macro.  But in my case,
at least, that's often not true.  It probably happens sometimes, but more
and more, it's rare, and I have good [private] macrology for managing this.

> It creates some weird code that
> has no simple representation. Worse. it might be completely replaced
> with a bunch of new things I would never associate with WITH-OPEN-FILE.
> When I want to edit source for the stack frame, it somehow has to figure
> out that there was some macro call and find it.

I just edit the thing on the stack frame and it takes me to the function that
is textually adjacent to the macro.

> WITH-OPEN-FILE also can't be composed
> with other functions.

I use my own CALL-WITH-OPEN-FILE if this is ever needed.  (I'm assuming 
we're talking about the general case of WITH-xxx macros, not specifically
WITH-OPEN-FILE.  If you're meaning to single out the one system function,
then I have no answer other than if I'd ever cared, I'd have written
CALL-WITH-OPEN-FILE as a function that used WITH-OPEN-FILE inside of it,
but I never have had the need.  To me, the need is theoretical, not 
practical.)

> I feel it is just in the way. In the
> source code it might look useful. But the one-2-one correspondence

(Heh.  one-to-one, I assume you mean.  Flanked by numbers, I guess 
the mind's temptation to substitute a digit is strong there.)

> of source and what I see on the stack is gone.

You could define a CALL-WITH-xxx wrapper.  It's not trivial to do if
you want access to system-defined keyword arguments, but it could be 
done with a little work, and probably even portably.

> I'm willing to
> give that up for IF, WHILE, LOOP and others - but somehow not
> for CALL-WITH-OPEN-FILE.

Heh.  Isn't the brain a marvelous thing? :) It just goes to underscore
my argument that the right simplicity metric for a language is not
"textual minimality" but rather "structural isomorphism to how people
think" (even knowing that this varies person to person, and that it's
hard to figure out precisely ... but it helps explain why a Lisp2 is a
rational concept).  I don't doubt you have just such an oddly placed
line in your head--I'm sure I have such a thing in a different place.
It's natural and normal.

> > I am NOT trying to say that you should believe these arguments, but can you
> > see how some of these things would matter to others?
> 
> Sure.

Phew. :)
From: Rainer Joswig
Subject: Re: A "killer" macro
Date: 
Message-ID: <joswig-7D3E29.11055413092007@news-europe.giganews.com>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> Before WITH-OPEN-FILE, I used to just use a LET with an OPEN, and I
> remember someone getting really mad at me one day on the PDP-10
> running the ITS operating system, which had only a finite number of
> file channels.  I'd used them all up, not realizing it, because the
> bindings were gone but the GC had not run (which would have closed
> them).  I asked what to do and no one had a good answer.  Soon after,
> there was an UNWIND-PROTECT added to the language, and I wrote a macro
> called IOTA (trying to make it greek so it would sound like LAMBDA, a
> binding form, but also like "I/O"). It allowed multiple binding forms,
> so it was easy to rewrite a LET into it.  I think that's how we
> started down the path to having it be a macro.  IOTA became widely
> used in MACLISP, at least at the MIT Lab for Computer Science--I don't
> know if it got distributed.  We weren't very formal about these things.
> [On another day, ask me about PI, the macro I wrote for binding...
> you guessed it... program interrupts.  It was later renamed to 
> WITHOUT-INTERRUPTS.]
> 
> Incidentally, too, back to CL, you should know that when I write these
> WITH-xxx macros, I almost always accompany them with a CALL-WITH-xxx
> so that I can do either kind of call.  But I find I almost never use
> the CALL-WITH-xxx even when I was the one to provide it as an option.
> The main reason I write them is not to use them but to make
> redefinition easier, since I can redefine the CALL-WITH-xxx without
> redefining the macro, and so I don't have to recompile the callers if
> the definition changes.

I agree, that's useful.

> 
> > One I also want to see on the stack. Directly. With
> > useful parameters. I could for example extract the DO-SOMETHING
> > function in a debugger and apply it to something. WITH-OPEN-FILE
> > is invisible on the stack.
> 
> Well, not the way I generally do it, so I mostly don't see this deficiency.
> (Note: I didn't say "I don't see this AS a deficiency", I mean it really
> isn't one because we (you and I) both see the same thing on the stack,
> since my macro call often expands into the function call that you wrote
> explicitly, and so at the time of looking on the stack, the textual pedigree
> of the call is long-since erased and the two techniques are blurred by
> a common functional implementation.)
> 
> Put another way, I often start with the implementation of the function you like
> and THEN write the macro because I hate its syntax.  You seem to be assuming
> I'm starting with a blank sheet and first writing a macro.  But in my case,
> at least, that's often not true.  It probably happens sometimes, but more
> and more, it's rare, and I have good [private] macrology for managing this.

I usually develop both together, experimenting a bit with the approaches
and try to find something that's a compromise of being elegant, minimal,
good to read and easy to debug. ;-) Sometimes I even might achieve that
goal. Macros as 'minimal art'.

> > It creates some weird code that
> > has no simple representation. Worse. it might be completely replaced
> > with a bunch of new things I would never associate with WITH-OPEN-FILE.
> > When I want to edit source for the stack frame, it somehow has to figure
> > out that there was some macro call and find it.
> 
> I just edit the thing on the stack frame and it takes me to the function that
> is textually adjacent to the macro.

I wish everybody would organize the code like you do. ;-)
Others please take that as good advice! ;-)

...

> > I'm willing to
> > give that up for IF, WHILE, LOOP and others - but somehow not
> > for CALL-WITH-OPEN-FILE.
> 
> Heh.  Isn't the brain a marvelous thing? :) It just goes to underscore
> my argument that the right simplicity metric for a language is not
> "textual minimality" but rather "structural isomorphism to how people
> think" (even knowing that this varies person to person, and that it's
> hard to figure out precisely ... but it helps explain why a Lisp2 is a
> rational concept).  I don't doubt you have just such an oddly placed
> line in your head--I'm sure I have such a thing in a different place.
> It's natural and normal.

Common Lisp is certainly a language that my thinking is comfortable with.
But it is more than the language. It is also the way you work
with the symbols of the program (in a general sense). For me
the environment is best when I have everything directly accessible,
no unnecessary hiding, things are descriptive and 'first class'.
C (and others) puts a wall between me and the data/program.
Common Lisp enables environments that let me work interactively.
I always feel pain when M-. is not working for some code or when things
look cryptic at runtime. The more I'm thinking about it in the last years,
the more I like 'symbolic programming'. Also 'Symbolics programming'.
;-) 

> > > I am NOT trying to say that you should believe these arguments, but can you
> > > see how some of these things would matter to others?
> > 
> > Sure.
> 
> Phew. :)

Relax!

-- 
http://lispm.dyndns.org
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kptupF4nol0U1@mid.individual.net>
Thomas F. Burdick wrote:
> On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
>> Eli Bendersky wrote:
>>
>>> I'm looking for that short - not too hard to
>>> understand - snippet of code that will show them *why*. I'm convinced
>>> that such a snippet must involve macros. But all the examples I ran
>>> into so far have been either too simple - and could be easily
>>> implemented another way (for example with Ruby's blocks), or too
>>> complicated.
>>> Any suggestions for such an example ?
>> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
> 
> The problem with this example is that, while it does demonstrate that
> macros are structural transforms of the code itself, it doesn't do
> anything that can't also be done in languages with light-weight
> lambdas.  Eg, if you were to look at Smalltalk code written by me,
> you'll notice things like:
> 
>   outfile withOutputStream: [:out |
>     infile doInputLines:
>       [:line | out nextLinePut: line]]
> 
> withOutputStream abstracting away the need for ensure: (ie, unwind-
> protect), and doInputLines: abstracting away that plus the loop of
> reading line-by-line while input is available.  While abstracting away
> the lambdas is a win for Lisp, that's not universal, so at least a
> doubtful ST'er won't see anything there.

That's why I said "my best attempt so far", and not "a good attempt." ;)

The two examples in that blog entry crystallize what I personally think 
is the essence of macros. I also noticed that many people don't get the 
second example though. It'd be nice to see another example that's 
equally compact and conveys the same idea.


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: Thomas F. Burdick
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189633531.845578.305720@o80g2000hse.googlegroups.com>
On Sep 12, 12:39 pm, Pascal Costanza <····@p-cos.net> wrote:
> Thomas F. Burdick wrote:
> > On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
> >> Eli Bendersky wrote:
>
> >>> I'm looking for that short - not too hard to
> >>> understand - snippet of code that will show them *why*. I'm convinced
> >>> that such a snippet must involve macros. But all the examples I ran
> >>> into so far have been either too simple - and could be easily
> >>> implemented another way (for example with Ruby's blocks), or too
> >>> complicated.
> >>> Any suggestions for such an example ?
> >> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
>
> > The problem with this example is that, while it does demonstrate that
> > macros are structural transforms of the code itself, it doesn't do
> > anything that can't also be done in languages with light-weight
> > lambdas.  Eg, if you were to look at Smalltalk code written by me,
> > you'll notice things like:
>
> >   outfile withOutputStream: [:out |
> >     infile doInputLines:
> >       [:line | out nextLinePut: line]]
>
> > withOutputStream abstracting away the need for ensure: (ie, unwind-
> > protect), and doInputLines: abstracting away that plus the loop of
> > reading line-by-line while input is available.  While abstracting away
> > the lambdas is a win for Lisp, that's not universal, so at least a
> > doubtful ST'er won't see anything there.
>
> That's why I said "my best attempt so far", and not "a good attempt." ;)

Yeah, I got that :-)
It is a difficult problem.

> The two examples in that blog entry crystallize what I personally think
> is the essence of macros. I also noticed that many people don't get the
> second example though. It'd be nice to see another example that's
> equally compact and conveys the same idea.

The big problem I see with those examples is that what they're trying
to use structural transformation as a lever to do is ... hide
lambdas.  I'm not really au courant of the most recent scripting
languages, but I have the impression that they're on an asymptotic
course not so much with Lisp as with Smalltalk.  So aiming one's
arguments at ST'ers might be overshooting, but that's okay.

For the problem of wanting to write your own "do while except return
when" control structure (to pick a silly example), there's a perfectly
good non-macro solution.  In ST, not only are anonymous functions
hilariously light-weight from a syntactic point of view, but the
*entire* language uses a dead-simple evaluation model: the receiving
expression is evaluated, then the arguments to pass with the message,
then the message is passed.  Always, that's it.  The language itself
doesn't really have special forms, they're all implemented as methods
-- which means that *all* divergences from the normal order of
evaluation use blocks, whether they be the super-banal ifTrue:ifFalse:
or my wacky doWhileTrue:exceptReturnWhen: [1].  This creates a
language ecology where a while/if/do-while-true-except-return-when
that works in a functional style does not in fact leak abstractions.
"This changes the order of evaluation" is part of the interface, not
the implementation.

Of course Lisp has special forms (like most languages).  In this
context, saying that one of the things the uniform syntax buys is
macros, and one of the uses of macros is to hide lambdas (which are
clumsy *not* because lambda is spelled l-a-m-b-d-a, but because the
built-in special forms work by magic, not via lambdas), therefore
macros let us extend the language in a seamless manner ... well, as
true as that is in the design ecology of the Lisp languages, it's very
much an argument trying to stand on its own shoulders from the point
of view of ST.  That's the sympathetic point of view -- it could also
be seen as an ex-post-facto justification of an ugly hack.

So, accepting that there are other combinations of language features
that take care of the lambda issue, what do macros buy you?  Not the
ability to add control structures that aren't primitively there (lack
of unwind-protect is not something you can solve with macros, no
matter how much I wish that it were so).  Not the ability to write
seamless DSL's (see Avi Bryant's Roe library for a lovely example of
how to incorporate relational algebra into the Smalltalk language).
No, I think the convincing examples will involve really using the
source forms as one of the macro parameters.

Speaking of which, that's actually a whole class of fairly simple,
more-or-less common macros.  with-slots and with-accessors are two
obvious examples.  Another one which pops to mind is:

  ;; collect strings describing all the entries in the songs table
  ;; in some SQL database
  (do-query ((name artist album) "songs"
             :where "genre = jazz and year > 1956")
    (push (format nil "~S by ~A on the album ~S" name artist album)
          songs))

The key thread here being that (a) variables are being bound based on
domain-specific information, and (b) one bit of that information is
the name of the variable itself.


[1] Just in case it's not obvious, a ST one would look like:

    [ x put i.
      i := i + 1
    ]
      doWhileTrue: [ i < 10000 ]
      exceptReturnWhen: [ i = z ]

  where Lisp would be either:

    (do-while-except
        (progn (my-push i x)
               (incf i))
      (< i 10000)
      :return-when (eql i z))

  or:

    (do-while-except-return-when
     (lambda () (my-push i x)
                (incf i))
     (lambda () (< i 10000))
     (lambda () (eql i z)))
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kuqjjF5jt13U1@mid.individual.net>
Thomas F. Burdick wrote:
>> The two examples in that blog entry crystallize what I personally think
>> is the essence of macros. I also noticed that many people don't get the
>> second example though. It'd be nice to see another example that's
>> equally compact and conveys the same idea.
> 
> The big problem I see with those examples is that what they're trying
> to use structural transformation as a lever to do is ... hide
> lambdas.  I'm not really au courant of the most recent scripting
> languages, but I have the impression that they're on an asymptotic
> course not so much with Lisp as with Smalltalk.  So aiming one's
> arguments at ST'ers might be overshooting, but that's okay.
> 
> For the problem of wanting to write your own "do while except return
> when" control structure (to pick a silly example), there's a perfectly
> good non-macro solution.

Sure. For example, you could implement them in assembly language.

> In ST, not only are anonymous functions
> hilariously light-weight from a syntactic point of view, but the
> *entire* language uses a dead-simple evaluation model: the receiving
> expression is evaluated, then the arguments to pass with the message,
> then the message is passed.  Always, that's it.  The language itself
> doesn't really have special forms, they're all implemented as methods
[...]

Of course, Smalltalk has special forms as well. For example, assignment, 
message selectors, message sending itself, etc.

Any language needs a set of core operators that are not derived from 
anything else.

> -- which means that *all* divergences from the normal order of
> evaluation use blocks, whether they be the super-banal ifTrue:ifFalse:
> or my wacky doWhileTrue:exceptReturnWhen: [1].  This creates a
> language ecology where a while/if/do-while-true-except-return-when
> that works in a functional style does not in fact leak abstractions.
> "This changes the order of evaluation" is part of the interface, not
> the implementation.

Of course, this leaks abstractions.

Assume you implement a functional version of if:

(defvar *true* (lambda (true false) (funcall true)))
(defvar *false* (lambda (true false) (funcall false)))

(defun f-if (pred then else)
   (funcall (funcall pred) then else))

(f-if (lambda () (if (< 1 10) *true* *false*))
   (lambda () (print 'less))
   (lambda () (print 'more)))

Now you realize that the first argument can be eagerly evaluated. You 
have to change your interface:

(defun f-if-2 (pred then else)
   (funcall pred then else))

(f-if-2 (if (< 1 10) *true* *false*)
   (lambda () (print 'less))
   (lambda () (print 'more)))

Whenever you have to change the interface because you want to change a 
mere implementation detail that doesn't add to the abstraction as such, 
your abstraction is leaking.


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: =?UTF-8?B?QWxla3NhbmRlciBOYWJhZ8WCbw==?=
Subject: Re: A "killer" macro
Date: 
Message-ID: <fcb5q2$l5d$1@srv.cyf-kr.edu.pl>
Pascal Costanza wrote:
> Thomas F. Burdick wrote:
>> On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
>>> Eli Bendersky wrote:
>>>
....
>> withOutputStream abstracting away the need for ensure: (ie, unwind-
>> protect), and doInputLines: abstracting away that plus the loop of
>> reading line-by-line while input is available.  While abstracting away
>> the lambdas is a win for Lisp, that's not universal, so at least a
>> doubtful ST'er won't see anything there.
> 
> That's why I said "my best attempt so far", and not "a good attempt." ;)
> 
> The two examples in that blog entry crystallize what I personally think 
> is the essence of macros. I also noticed that many people don't get the 
> second example though. It'd be nice to see another example that's 
> equally compact and conveys the same idea.

;;; horner-ex.lisp
(defun horner-ex (x aa)
   (flet ((hrn (a b) `(+ ,a (* ,x ,b))))
     (labels ((hrn-re (aa)
	       (if (cdr aa)
		   (hrn (car aa) (hrn-re (cdr aa)))
		   (car aa))))
       (hrn-re aa))))
	
(defmacro horner-def (h x &rest r)
   `(defun ,h (,x) ,(horner-ex x r)))



;; Dribble of #<IO TERMINAL-STREAM> started 2007-09-13 13:01:49
#<OUTPUT BUFFERED FILE-STREAM CHARACTER #P"horner.txt">
[2]> (load "horner-ex.lisp")
;; Loading file horner-ex.lisp ...
;; Loaded file horner-ex.lisp
T
[3]> (horner-def alfa x 1 2 3)
ALFA
[4]> (alfa 2)
17
[5]> (alfa 3)
34
[6]> (symbol-function 'alfa)
#<FUNCTION ALFA (X) (DECLARE (SYSTEM::IN-DEFUN ALFA)) (BLOCK ALFA (+ 1 
(* X (+ 2 (* X 3)))))>
[7]> (horner-def alfa y 2D0 (/ 7D0) 4D0 5D0)
ALFA
[8]> (alfa 2D0)
58.285714285714285d0
[9]> (alfa 3D0)
173.42857142857144d0
[10]> (symbol-function 'alfa)
#<FUNCTION ALFA (Y) (DECLARE (SYSTEM::IN-DEFUN ALFA))
   (BLOCK ALFA (+ 2.0d0 (* Y (+ (/ 7.0d0) (* Y (+ 4.0d0 (* Y 5.0d0)))))))>
[11]> (exit)

-- 
A
.
From: Dimiter "malkia" Stanev
Subject: Re: A "killer" macro
Date: 
Message-ID: <5ktp97F5cofkU1@mid.individual.net>
Thanks for that! Nice example!

Aleksander Nabagło wrote:
> Pascal Costanza wrote:
>> Thomas F. Burdick wrote:
>>> On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
>>>> Eli Bendersky wrote:
>>>>
> .....
>>> withOutputStream abstracting away the need for ensure: (ie, unwind-
>>> protect), and doInputLines: abstracting away that plus the loop of
>>> reading line-by-line while input is available.  While abstracting away
>>> the lambdas is a win for Lisp, that's not universal, so at least a
>>> doubtful ST'er won't see anything there.
>>
>> That's why I said "my best attempt so far", and not "a good attempt." ;)
>>
>> The two examples in that blog entry crystallize what I personally 
>> think is the essence of macros. I also noticed that many people don't 
>> get the second example though. It'd be nice to see another example 
>> that's equally compact and conveys the same idea.
> 
> ;;; horner-ex.lisp
> (defun horner-ex (x aa)
>   (flet ((hrn (a b) `(+ ,a (* ,x ,b))))
>     (labels ((hrn-re (aa)
>            (if (cdr aa)
>            (hrn (car aa) (hrn-re (cdr aa)))
>            (car aa))))
>       (hrn-re aa))))
>     
> (defmacro horner-def (h x &rest r)
>   `(defun ,h (,x) ,(horner-ex x r)))
> 
> 
> 
> ;; Dribble of #<IO TERMINAL-STREAM> started 2007-09-13 13:01:49
> #<OUTPUT BUFFERED FILE-STREAM CHARACTER #P"horner.txt">
> [2]> (load "horner-ex.lisp")
> ;; Loading file horner-ex.lisp ...
> ;; Loaded file horner-ex.lisp
> T
> [3]> (horner-def alfa x 1 2 3)
> ALFA
> [4]> (alfa 2)
> 17
> [5]> (alfa 3)
> 34
> [6]> (symbol-function 'alfa)
> #<FUNCTION ALFA (X) (DECLARE (SYSTEM::IN-DEFUN ALFA)) (BLOCK ALFA (+ 1 
> (* X (+ 2 (* X 3)))))>
> [7]> (horner-def alfa y 2D0 (/ 7D0) 4D0 5D0)
> ALFA
> [8]> (alfa 2D0)
> 58.285714285714285d0
> [9]> (alfa 3D0)
> 173.42857142857144d0
> [10]> (symbol-function 'alfa)
> #<FUNCTION ALFA (Y) (DECLARE (SYSTEM::IN-DEFUN ALFA))
>   (BLOCK ALFA (+ 2.0d0 (* Y (+ (/ 7.0d0) (* Y (+ 4.0d0 (* Y 5.0d0)))))))>
> [11]> (exit)
> 
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189594858.581225.193980@o80g2000hse.googlegroups.com>
On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
> Eli Bendersky wrote:
> > Hello all,
>
> > In short: I'm looking for a "killer" macro - a macro (or a couple of
> > related ones) that show what Lisp can do and other languages (those
> > without uniform syntax) can not.
>
> > A longer version: Many contemporary languages boast their sharing most
> > of the functional features of Lisp. Perl, Ruby, Javascript - all have
> > convenient lists (or arrays), functions as first class objects,
> > garbage collection, dynamic typing, lexical closures. However, one
> > thing they lack is uniform syntax, and hence the service of a powerful
> > built-in macro system such as Common Lisp's "defmacro".
> > When confronted by fellow programmers with the question "so why is
> > Lisp so special", I'm looking for that short - not too hard to
> > understand - snippet of code that will show them *why*. I'm convinced
> > that such a snippet must involve macros. But all the examples I ran
> > into so far have been either too simple - and could be easily
> > implemented another way (for example with Ruby's blocks), or too
> > complicated.
>
> > Any suggestions for such an example ?
>
> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
>

Pascal, this can be achieved in Ruby in a simpler way, so it won't
cut.

I think that the direction should be towards some brilliant example of
a simple DSL that looks like any other Lisp code. *this* can't be done
in a non-uniform syntax language.

Eli
From: Tim Bradshaw
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189597624.755329.62390@50g2000hsm.googlegroups.com>
On Sep 12, 12:00 pm, Eli Bendersky <······@gmail.com> wrote:

> I think that the direction should be towards some brilliant example of
> a simple DSL that looks like any other Lisp code. *this* can't be done
> in a non-uniform syntax language.

The canonical DSL that looks like any other Lisp code is HTML
From: Andy Chambers
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189604641.526672.11710@w3g2000hsg.googlegroups.com>
On 12 Sep, 12:47, Tim Bradshaw <··········@tfeb.org> wrote:
> On Sep 12, 12:00 pm, Eli Bendersky <······@gmail.com> wrote:
>
> > I think that the direction should be towards some brilliant example of
> > a simple DSL that looks like any other Lisp code. *this* can't be done
> > in a non-uniform syntax language.
>
> The canonical DSL that looks like any other Lisp code is HTML

I think that html "templating" might be a contender.  There's probably
nothing lisp can do that nothing else can if the "else" is allowed
unlimited code but I bet cl-who (or aserve's offering) uses a lot less
code than any of the php/python/ruby template engine's and the code
that uses it looks better too.

--
Andy
From: Zach Beane
Subject: Re: A "killer" macro
Date: 
Message-ID: <m3lkbcqbbn.fsf@unnamed.xach.com>
Eli Bendersky <······@gmail.com> writes:

> I think that the direction should be towards some brilliant example of
> a simple DSL that looks like any other Lisp code. *this* can't be done
> in a non-uniform syntax language.

Here are a couple of my favorite examples:

  - http://groups.google.com/group/comp.lang.lisp/msg/2ff89986ee77f639

  - http://groups.google.com/group/comp.lang.lisp/msg/86cf454beb8a42f9

Zach
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kq2t0F50i9fU1@mid.individual.net>
Eli Bendersky wrote:
> On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
>> Eli Bendersky wrote:
>>> Hello all,
>>> In short: I'm looking for a "killer" macro - a macro (or a couple of
>>> related ones) that show what Lisp can do and other languages (those
>>> without uniform syntax) can not.
>>> A longer version: Many contemporary languages boast their sharing most
>>> of the functional features of Lisp. Perl, Ruby, Javascript - all have
>>> convenient lists (or arrays), functions as first class objects,
>>> garbage collection, dynamic typing, lexical closures. However, one
>>> thing they lack is uniform syntax, and hence the service of a powerful
>>> built-in macro system such as Common Lisp's "defmacro".
>>> When confronted by fellow programmers with the question "so why is
>>> Lisp so special", I'm looking for that short - not too hard to
>>> understand - snippet of code that will show them *why*. I'm convinced
>>> that such a snippet must involve macros. But all the examples I ran
>>> into so far have been either too simple - and could be easily
>>> implemented another way (for example with Ruby's blocks), or too
>>> complicated.
>>> Any suggestions for such an example ?
>> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
> 
> Pascal, this can be achieved in Ruby in a simpler way, so it won't
> cut.

No, you can't do this in Ruby at all.

It's important to understand why that's the case.

I agree that it's easy to miss the difference, so maybe it's not a good 
illustration for that reason. But the difference is definitely there.


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: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189601798.283143.311630@57g2000hsv.googlegroups.com>
On Sep 12, 2:03 pm, Pascal Costanza <····@p-cos.net> wrote:
> Eli Bendersky wrote:
> > On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
> >> Eli Bendersky wrote:
> >>> Hello all,
> >>> In short: I'm looking for a "killer" macro - a macro (or a couple of
> >>> related ones) that show what Lisp can do and other languages (those
> >>> without uniform syntax) can not.
> >>> A longer version: Many contemporary languages boast their sharing most
> >>> of the functional features of Lisp. Perl, Ruby, Javascript - all have
> >>> convenient lists (or arrays), functions as first class objects,
> >>> garbage collection, dynamic typing, lexical closures. However, one
> >>> thing they lack is uniform syntax, and hence the service of a powerful
> >>> built-in macro system such as Common Lisp's "defmacro".
> >>> When confronted by fellow programmers with the question "so why is
> >>> Lisp so special", I'm looking for that short - not too hard to
> >>> understand - snippet of code that will show them *why*. I'm convinced
> >>> that such a snippet must involve macros. But all the examples I ran
> >>> into so far have been either too simple - and could be easily
> >>> implemented another way (for example with Ruby's blocks), or too
> >>> complicated.
> >>> Any suggestions for such an example ?
> >> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
>
> > Pascal, this can be achieved in Ruby in a simpler way, so it won't
> > cut.
>
> No, you can't do this in Ruby at all.
>
> It's important to understand why that's the case.
>
> I agree that it's easy to miss the difference, so maybe it's not a good
> illustration for that reason. But the difference is definitely there.
>

What, specifically, can't you do ?  with-open-file ? while ?
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kq6f0F4s9pdU1@mid.individual.net>
Eli Bendersky wrote:
> On Sep 12, 2:03 pm, Pascal Costanza <····@p-cos.net> wrote:
>> Eli Bendersky wrote:
>>> On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
>>>> Eli Bendersky wrote:
>>>>> Hello all,
>>>>> In short: I'm looking for a "killer" macro - a macro (or a couple of
>>>>> related ones) that show what Lisp can do and other languages (those
>>>>> without uniform syntax) can not.
>>>>> A longer version: Many contemporary languages boast their sharing most
>>>>> of the functional features of Lisp. Perl, Ruby, Javascript - all have
>>>>> convenient lists (or arrays), functions as first class objects,
>>>>> garbage collection, dynamic typing, lexical closures. However, one
>>>>> thing they lack is uniform syntax, and hence the service of a powerful
>>>>> built-in macro system such as Common Lisp's "defmacro".
>>>>> When confronted by fellow programmers with the question "so why is
>>>>> Lisp so special", I'm looking for that short - not too hard to
>>>>> understand - snippet of code that will show them *why*. I'm convinced
>>>>> that such a snippet must involve macros. But all the examples I ran
>>>>> into so far have been either too simple - and could be easily
>>>>> implemented another way (for example with Ruby's blocks), or too
>>>>> complicated.
>>>>> Any suggestions for such an example ?
>>>> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
>>> Pascal, this can be achieved in Ruby in a simpler way, so it won't
>>> cut.
>> No, you can't do this in Ruby at all.
>>
>> It's important to understand why that's the case.
>>
>> I agree that it's easy to miss the difference, so maybe it's not a good
>> illustration for that reason. But the difference is definitely there.
>>
> 
> What, specifically, can't you do ?  with-open-file ? while ?

While without lambdas (or blocks, or whatever you want to call them).


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: Brian Adkins
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189612462.692141.20490@r34g2000hsd.googlegroups.com>
On Sep 12, 9:04 am, Pascal Costanza <····@p-cos.net> wrote:
> Eli Bendersky wrote:
> > What, specifically, can't you do ?  with-open-file ? while ?
>
> While without lambdas (or blocks, or whatever you want to call them).
>
> Pascal

I think Eli was focused on the first example in the article (possibly
because it was the first example) which is easy to do in Ruby with a
block:

File.open(filename) {|in| do_something(in) }

I think you're right about not being able to do while w/o lambdas, but
it's not too bad (syntactically) with them. The efficiency is worse
than macros, but then Ruby is dog slow anyway:

def while_function pred, &b
  if pred.call
    yield
    while_function(pred, &b)
  end
end

n = 3
while_function(lambda { n > 0 }) do
  puts n
  n -=1
end

Having notational convenience via macros plus efficiency is a big win
with Lisp. From my perspective as a Ruby programmer learning Lisp, the
thought of having a more powerful language *and* order(s) of magnitude
faster execution felt like having my cake and eating it too.
From: Thomas A. Russ
Subject: Re: A "killer" macro
Date: 
Message-ID: <ymik5qvaaws.fsf@blackcat.isi.edu>
Brian Adkins <···········@gmail.com> writes:

> On Sep 12, 9:04 am, Pascal Costanza <····@p-cos.net> wrote:
> > Eli Bendersky wrote:
> > > What, specifically, can't you do ?  with-open-file ? while ?
> >
> > While without lambdas (or blocks, or whatever you want to call them).
> >
> > Pascal
> 
> I think Eli was focused on the first example in the article (possibly
> because it was the first example) which is easy to do in Ruby with a
> block:
> 
> File.open(filename) {|in| do_something(in) }
> 
> I think you're right about not being able to do while w/o lambdas, but
> it's not too bad (syntactically) with them. The efficiency is worse
> than macros, but then Ruby is dog slow anyway:

Well, the point here would be:  How could you implement that in Ruby IF
the language didn't already have it in the first place?  In other words,
could you add something that works like that syntactically if the
compiler writers and language designers HAD NOT ALREADY built it for
you?

That's the beauty of Lisp macros.  You can add them.

Loop is an example of an iteration construct that was (quite literally)
added to the lisp language through macro programming.  And for those who
don't like loop, there's series.  How many languages would let you
create a WHILE or a FOR loop construct when the language didn't already
support it?


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Brian Adkins
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189654637.518668.188390@r29g2000hsg.googlegroups.com>
On Sep 12, 4:25 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> Well, the point here would be:  How could you implement that in Ruby IF
> the language didn't already have it in the first place?  In other words,
> could you add something that works like that syntactically if the
> compiler writers and language designers HAD NOT ALREADY built it for
> you?
>
> That's the beauty of Lisp macros.  You can add them.

What part of "notational convenience", "power", "efficiency", etc. did
you not understand? And stop the shouting already :) You're preaching
to the choir dude. Even as a newbie I can appreciate Lisp's macros -
the programmable programming language, etc.

The op asked for examples of macros to show off to his ignorant
friends/colleagues. Instead of showing off macros that implement
something that *is* already in a particular language, why not show off
a macro that adds something that *isn't* already in the language?
Showing a Ruby programmer a macro that does essentially the same thing
as File.open(filename) {|in| do_something(in) }  and then telling him
how lame Ruby is because if the feature wasn't *already in the
language* it would be hard to add, may not be impressive.

Would you agree that languages such as Ruby have traded the
flexibility, generality & uniformity that Lisp provides for notational
convenience, etc.? So why not show a macro example that accentuates
the strength of Lisp and weakness of language X in a particular
context instead of showing one that simply implements a pre-existing
feature?
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189673662.302089.75490@y42g2000hsy.googlegroups.com>
On Sep 12, 5:54 pm, Brian Adkins <···········@gmail.com> wrote:
> On Sep 12, 9:04 am, Pascal Costanza <····@p-cos.net> wrote:
>
> > Eli Bendersky wrote:
> > > What, specifically, can't you do ?  with-open-file ? while ?
>
> > While without lambdas (or blocks, or whatever you want to call them).
>
> > Pascal
>
> I think Eli was focused on the first example in the article (possibly
> because it was the first example) which is easy to do in Ruby with a
> block:
>
> File.open(filename) {|in| do_something(in) }
>
> I think you're right about not being able to do while w/o lambdas, but
> it's not too bad (syntactically) with them. The efficiency is worse
> than macros, but then Ruby is dog slow anyway:
>
> def while_function pred, &b
>   if pred.call
>     yield
>     while_function(pred, &b)
>   end
> end
>
> n = 3
> while_function(lambda { n > 0 }) do
>   puts n
>   n -=1
> end
>
> Having notational convenience via macros plus efficiency is a big win
> with Lisp. From my perspective as a Ruby programmer learning Lisp, the
> thought of having a more powerful language *and* order(s) of magnitude
> faster execution felt like having my cake and eating it too.

Thanks for this, it is exactly what I intended to write. These
examples just show something that's slightly more elegant in Lisp than
in Ruby. Hardly a reason for all Lispers to brag how superior their
language is.

Unfortunately, 40+ posts into this thread, there still is no real
answer.

Eli
From: ··············@yahoo.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189690530.155506.88320@22g2000hsm.googlegroups.com>
> Hardly a reason for all Lispers to brag how superior their
> language is.
>
> Unfortunately, 40+ posts into this thread, there still is no real
> answer.

Perhaps there really is no "answer" to speak of.  Perhaps the answer
is simply "you like lisp, so program in lisp, and leave others to
their own devices."
From: Rainer Joswig
Subject: Re: A "killer" macro
Date: 
Message-ID: <joswig-D3D4FA.11350413092007@news-europe.giganews.com>
In article <·······················@y42g2000hsy.googlegroups.com>,
 Eli Bendersky <······@gmail.com> wrote:

> On Sep 12, 5:54 pm, Brian Adkins <···········@gmail.com> wrote:
> > On Sep 12, 9:04 am, Pascal Costanza <····@p-cos.net> wrote:
> >
> > > Eli Bendersky wrote:
> > > > What, specifically, can't you do ?  with-open-file ? while ?
> >
> > > While without lambdas (or blocks, or whatever you want to call them).
> >
> > > Pascal
> >
> > I think Eli was focused on the first example in the article (possibly
> > because it was the first example) which is easy to do in Ruby with a
> > block:
> >
> > File.open(filename) {|in| do_something(in) }
> >
> > I think you're right about not being able to do while w/o lambdas, but
> > it's not too bad (syntactically) with them. The efficiency is worse
> > than macros, but then Ruby is dog slow anyway:
> >
> > def while_function pred, &b
> >   if pred.call
> >     yield
> >     while_function(pred, &b)
> >   end
> > end
> >
> > n = 3
> > while_function(lambda { n > 0 }) do
> >   puts n
> >   n -=1
> > end
> >
> > Having notational convenience via macros plus efficiency is a big win
> > with Lisp. From my perspective as a Ruby programmer learning Lisp, the
> > thought of having a more powerful language *and* order(s) of magnitude
> > faster execution felt like having my cake and eating it too.
> 
> Thanks for this, it is exactly what I intended to write. These
> examples just show something that's slightly more elegant in Lisp than
> in Ruby. Hardly a reason for all Lispers to brag how superior their
> language is.
> 
> Unfortunately, 40+ posts into this thread, there still is no real
> answer.
> 
> Eli


"Sie sehn den Wald vor lauter Baumen nicht."

-- 
http://lispm.dyndns.org
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kurijF5m4mkU1@mid.individual.net>
Eli Bendersky wrote:
> On Sep 12, 5:54 pm, Brian Adkins <···········@gmail.com> wrote:
>> On Sep 12, 9:04 am, Pascal Costanza <····@p-cos.net> wrote:
>>
>>> Eli Bendersky wrote:
>>>> What, specifically, can't you do ?  with-open-file ? while ?
>>> While without lambdas (or blocks, or whatever you want to call them).
>>> Pascal
>> I think Eli was focused on the first example in the article (possibly
>> because it was the first example) which is easy to do in Ruby with a
>> block:
>>
>> File.open(filename) {|in| do_something(in) }
>>
>> I think you're right about not being able to do while w/o lambdas, but
>> it's not too bad (syntactically) with them. The efficiency is worse
>> than macros, but then Ruby is dog slow anyway:
>>
>> def while_function pred, &b
>>   if pred.call
>>     yield
>>     while_function(pred, &b)
>>   end
>> end
>>
>> n = 3
>> while_function(lambda { n > 0 }) do
>>   puts n
>>   n -=1
>> end
>>
>> Having notational convenience via macros plus efficiency is a big win
>> with Lisp. From my perspective as a Ruby programmer learning Lisp, the
>> thought of having a more powerful language *and* order(s) of magnitude
>> faster execution felt like having my cake and eating it too.
> 
> Thanks for this, it is exactly what I intended to write. These
> examples just show something that's slightly more elegant in Lisp than
> in Ruby. Hardly a reason for all Lispers to brag how superior their
> language is.
> 
> Unfortunately, 40+ posts into this thread, there still is no real
> answer.

It's important to step two or three steps back at this stage:

No language is objectively "better" than any other. As long as a 
language is Turing complete and has good access to the capabilities of 
the underlying operating system, you can do whatever you want in it. 
Turing equivalence means that whenever you can express something in one 
language, you can also express it in another.

The _only_ differences between programming languages that matter are 
those of convenience, and convenience is a highly subjective matter. 
Some people prefer to exclusively think in a functional style, some 
people prefer to exclusively think in an object-oriented style, some 
people only feel comfortable if a language allows them to formally prove 
certain aspects of their programs, some people want a large library so 
they don't have to program a lot themselves, some people prefer a 
minimal set of language constructs because they are bad at remembering 
more, some people prefer to mix and match paradigms as they go, some 
people prefer to remain pure, and so on, and so on, ad infinitum.

These are all trade offs, and there is no single best choice that suits 
everyone in all contexts one can think of. At some stage, there is no 
other way than to just make a decision and go with one language, or a 
couple of them, based on personal preferences, and stick to that 
decision at least for a while.

This doesn't mean that you cannot make objective statements about 
certain language constructs. And that's the _only_ thing I wanted to 
make in my blog posting about what I think is the point of macros.

It's an objective truth that you can create syntactic abstractions with 
macros, and that they allow you to hide implementation details that you 
cannot hide in any other way. Functional abstractions are leaky in 
certain regards which can only be fixed by macros in the general case. 
Yes, there are always ways to provide workarounds in one or the other 
language (lazy evaluation, light-weight syntax for lambda expressions, 
etc.), but none of them does this in such a fundamental way as macros 
do. [1]

I couldn't care less whether you think that this buys you a lot or not. 
That's a subjective value judgement, and I don't know enough about your 
personal preferences to make any claims about them. I can only state 
that I know that the objective increase in expressiveness that macros 
provide is important _to me_ from the perspective of _my_ personal 
preferences, and I can inform you about this. Afterwards, you have to 
make your own choice.


Pascal

[1] Except for fexprs or nlambdas in some Lisp dialects, but that's a 
different topic.

-- 
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: Rainer Joswig
Subject: Re: A "killer" macro
Date: 
Message-ID: <joswig-F8C4BA.10420114092007@news-europe.giganews.com>
In article <··············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Eli Bendersky wrote:
> > On Sep 12, 5:54 pm, Brian Adkins <···········@gmail.com> wrote:
> >> On Sep 12, 9:04 am, Pascal Costanza <····@p-cos.net> wrote:
> >>
> >>> Eli Bendersky wrote:
> >>>> What, specifically, can't you do ?  with-open-file ? while ?
> >>> While without lambdas (or blocks, or whatever you want to call them).
> >>> Pascal
> >> I think Eli was focused on the first example in the article (possibly
> >> because it was the first example) which is easy to do in Ruby with a
> >> block:
> >>
> >> File.open(filename) {|in| do_something(in) }
> >>
> >> I think you're right about not being able to do while w/o lambdas, but
> >> it's not too bad (syntactically) with them. The efficiency is worse
> >> than macros, but then Ruby is dog slow anyway:
> >>
> >> def while_function pred, &b
> >>   if pred.call
> >>     yield
> >>     while_function(pred, &b)
> >>   end
> >> end
> >>
> >> n = 3
> >> while_function(lambda { n > 0 }) do
> >>   puts n
> >>   n -=1
> >> end
> >>
> >> Having notational convenience via macros plus efficiency is a big win
> >> with Lisp. From my perspective as a Ruby programmer learning Lisp, the
> >> thought of having a more powerful language *and* order(s) of magnitude
> >> faster execution felt like having my cake and eating it too.
> > 
> > Thanks for this, it is exactly what I intended to write. These
> > examples just show something that's slightly more elegant in Lisp than
> > in Ruby. Hardly a reason for all Lispers to brag how superior their
> > language is.
> > 
> > Unfortunately, 40+ posts into this thread, there still is no real
> > answer.
> 
> It's important to step two or three steps back at this stage:
> 
> No language is objectively "better" than any other. As long as a 
> language is Turing complete and has good access to the capabilities of 
> the underlying operating system, you can do whatever you want in it. 
> Turing equivalence means that whenever you can express something in one 
> language, you can also express it in another.

This need to be 'superior' or 'better' is bullshit. A programming language
is not just a bunch of technical features with 'objective'
criteria to rank them.

Programmer's needs and capabilities are vastly different.
Programming languages are like a social eco-system. Plus
there is human behavior engraved into our brains. For example
people have the tendency to like what they already know. There
is a hurdle to unlearn or relearn.

I simply doubt we
can judge whether Lisp is useful to somebody because we
saw a cute macro example in some newsgroup. Macros might
even be the wrong thing for the typical Ruby user.
It might change the language in a way that makes it
too complicated for many users.

If languages like Ruby or Python appeal to many people,
that is perfectly fine. They have a large community,
share lots of stuff, are friendly within their communities
and so on. Technically there are a few differences, but
mostly they provide a kind of object-oriented programming
experience with some 'scripting' built-in.

Now people from the outside look at Lisp. It is still there
after almost 50 years. It must be superior. Or not? Then one
hears vague claims that it is better and some propaganda.
Now people here in comp.lang.lisp are questioned over and
over, why Lisp is better than X, Y, Z. For what definition
of better I have to ask? If Ruby has the library and
the programming model that you need and understand, then there
is a hurdle to overcome to understand Lisp, find a library
or maybe create a library yourself? Is the learning effort
worth it? Is Lisp so much 'better' that the effort to learn
it is well spend. Hard to say.

From my side, I also look at, say, Ruby. Then I think is it
worth it to learn it or even to use it? Would it pay
back? Much what I know from Lisp applies directly
to programming with Ruby. There is little advantage to switch.
Still it is useful to understand where things are heading
in terms of libraries, usability, infrastructure and so on.


But coming back to macros. There are some programming styles
in Lisp where you see lots of macros. Many examples
can be found in Paul Graham's book 'On Lisp'
(available as PDF here: http://lib.store.yahoo.net/lib/paulgraham/onlisp.pdf ).
It covers many/most uses of macros.

Then is some software (in this case CL-HTTP) you see a snippet of code like this:


(defmethod copy-file (from-pathname to-pathname &key (copy-mode :text) (copy-creation-date t) report-stream &allow-other-keys)
  (with-copy-file-environment (from-pathname to-pathname report-stream)
    (let ((element-type (copy-mode-element-type copy-mode))
          modification-date creation-date author)
      (with-open-file (from from-pathname :direction :input :element-type element-type :if-does-not-exist :error)
         (with-open-file (to to-pathname :direction :output :element-type element-type :if-exists :supersede
                                         :if-does-not-exist :create)
            (stream-copy-until-eof from to copy-mode))
   (when copy-creation-date
     (cond-every
       ((setq modification-date (file-stream-modification-date from))
        (setf (file-modification-date to-pathname) modification-date)) 
       ((setq creation-date (file-stream-creation-date from))
        (setf (file-creation-date to-pathname) creation-date)))))
     (when (and copy-creation-date (setq author (file-author from-pathname)))
       (set-file-author to-pathname author nil))
     to-pathname)))

Macros are DEFMETHOD, WITH-COPY-FILE-ENVIRONMENT, WITH-OPEN-FILE, COND-EVERY, SETF, WHEN.

So we have built-in macros DEFMETHOD, WITH-OPEN-FILE, SETF and WHEN.
The author added WITH-COPY-FILE-ENVIRONMENT and COND-EVERY.
COND-EVERY is just a version of COND that checks every clause.
It expands to some efficient low-level form without the need to introduce
anonymous functions (or BLOCKs in Ruby).

WITH-COPY-FILE-ENVIRONMENT is one of those WITH- macros that set a scope and inside the scope
there is some effect.

In this case it hides the handling of errors and providing of restarts:

(defmacro with-copy-file-environment ((from to stream &optional (block-name 'copy-file))                                                                   
                                      &body body)                                                                                                          
  `(tagbody                                                                                                                                                
    retry                                                                                                                                                  
    (when ,stream                                                                                                                                          
      (format ,stream "~&Copying ~A to ~A . . ." (name-string ,from) (name-string ,to)))                                                                   
    (restart-case                                                                                                                                          
        (return-from ,block-name                                                                                                                           
          (multiple-value-prog1 (progn ,@body)                                                                                                             
            (when ,stream                                                                                                                                  
              (format ,stream "~&Copied ~A to ~A." (name-string ,from)                                                                                     
                      (name-string ,to)))))                                                                                                                
      (retry ()                                                                                                                                            
        :report (lambda (stream)                                                                                                                           
                  (format stream "Retry copying ~A" (name-string ,from)))                                                                                  
        (go retry))                                                                                                                                        
      (skip ()                                                                                                                                             
        :report (lambda (stream)                                                                                                                           
                  (format stream "Skip copying ~A" (name-string ,from)))                                                                                   
        (when ,stream                                                                                                                                      
          (format ,stream "~A not copied." (name-string ,from)))                                                                                           
        (return-from ,block-name nil)))))

Above is one of the examples where a template like approach to code generation is sufficient.
The macro completely decouples the complex handling logic from the code in COPY-FILE.
The macro provides RESTARTs for RETRY and SKIP. Whenever there is an error during copying
a file to another, the user will get these two restarts.

The USER code in COPY-FILE is uncluttered. The complex stuff is reusable in the macro.

Let's check a simple use:

(let ((from (pathname "/tmp/test10.lisp"))                                                                                                                 
      (to (pathname "/tmp/test11.lisp")))                                                                                                                  
  (with-copy-file-environment (from to *standard-output*)                                                                                                  
    (error "just an example")))

SLIME shows me the following display in the debugger. Note that our new RESTARTs are available.

Execution of a form compiled with errors:                                                                                                            
 (RETURN-FROM COPY-FILE                                                                                                                              
   (MULTIPLE-VALUE-PROG1                                                                                                                             
       (PROGN                                                                                                                                        
         (ERROR "just an example"))                                                                                                                  
     (WHEN *STANDARD-OUTPUT*                                                                                                                         
       (FORMAT *STANDARD-OUTPUT* "~&Copied ~A to ~A." # #))))
   [Condition of type KERNEL:SIMPLE-PROGRAM-ERROR]

Restarts:
 0: [RETRY] Retry copying /tmp/test10.lisp
 1: [SKIP] Skip copying /tmp/test10.lisp
 2: [ABORT] Return to SLIME's top level.
 3: [ABORT] Return to Top-Level.

Backtrace:
  0: ("Top-Level Form")[:TOP-LEVEL]
  1: ("Top-Level Form")[:TOP-LEVEL]
  2: ("Top-Level Form")[:TOP-LEVEL]
 --more--


If you use, say, CMUCL without Emacs and Slime, the it looks like this:

* (let ((from (pathname "/tmp/test10.lisp"))                                                                                                                 
      (to (pathname "/tmp/test11.lisp")))                                                                                                                  
  (with-copy-file-environment (from to *standard-output*)                                                                                                  
    (error "just an example")))

Execution of a form compiled with errors:
 (RETURN-FROM COPY-FILE
   (MULTIPLE-VALUE-PROG1
       (PROGN
         (ERROR "just an example"))
     (WHEN *STANDARD-OUTPUT*
       (FORMAT *STANDARD-OUTPUT*
               "~&Copied ~A to ~A."
               (NAME-STRING FROM)
               (NAME-STRING TO)))))
   [Condition of type KERNEL:SIMPLE-PROGRAM-ERROR]

Restarts:
  0: [RETRY] Retry copying /tmp/test10.lisp
  1: [SKIP ] Skip copying /tmp/test10.lisp
  2: [ABORT] Return to Top-Level.

Debug  (type H for help)

("Top-Level Form")[:TOP-LEVEL]
Source: (WITH-COPY-FILE-ENVIRONMENT (FROM TO *STANDARD-OUTPUT*)
                                    (ERROR "just an example"))
0] 


We see in the terminal that our RESTARTs are there. One Restart which was added by SLIME is no longer there,
since we don't run it with SLIME in this example.


He, you got a few things in one example:

* how you can extract complex control flow code with a macro from user code

* how a macro looks like that uses a template like code generation

* how the CONDITION system lets you add user visible RESTARTs.

Isn't that nice.

-- 
http://lispm.dyndns.org
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kv681F5jsceU3@mid.individual.net>
Rainer Joswig wrote:
> This need to be 'superior' or 'better' is bullshit. A programming language
> is not just a bunch of technical features with 'objective'
> criteria to rank them.
> 
> Programmer's needs and capabilities are vastly different.
> Programming languages are like a social eco-system. Plus
> there is human behavior engraved into our brains. For example
> people have the tendency to like what they already know. There
> is a hurdle to unlearn or relearn.

I totally agree.

> I simply doubt we
> can judge whether Lisp is useful to somebody because we
> saw a cute macro example in some newsgroup.

Especially because macros - like any other metaprogramming approach - 
only really pay off in large and complex systems, where it is worthwhile 
to condense involved and longish code patterns into smaller units.


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: Slobodan Blazeski
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189769023.284989.297410@19g2000hsx.googlegroups.com>
On Sep 14, 12:31 pm, Pascal Costanza <····@p-cos.net> wrote:
> Rainer Joswig wrote:
> > This need to be 'superior' or 'better' is bullshit. A programming language
> > is not just a bunch of technical features with 'objective'
> > criteria to rank them.
>
> > Programmer's needs and capabilities are vastly different.
> > Programming languages are like a social eco-system. Plus
> > there is human behavior engraved into our brains. For example
> > people have the tendency to like what they already know. There
> > is a hurdle to unlearn or relearn.
>
> I totally agree.
>
> > I simply doubt we
> > can judge whether Lisp is useful to somebody because we
> > saw a cute macro example in some newsgroup.
>
> Especially because macros - like any other metaprogramming approach -
> only really pay off in large and complex systems, where it is worthwhile
> to condense involved and longish code patterns into smaller units.
>
> 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/
Question: How does a large software project get to be one year late?
Answer: One day at a time!
Fred Brooks-The Mythical Man-Month

Metaprogramming pays very well in medium size projects also , beside
condesing code, there is the utility syndrom. If you write something
usefull you tend to use it, again and again and again.
While ago I wrote a simple one liner called string+, and now I lost
count how many  times I use it. It's contagious.
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kvb3kF5n8dhU1@mid.individual.net>
Slobodan Blazeski wrote:
> On Sep 14, 12:31 pm, Pascal Costanza <····@p-cos.net> wrote:
>> Rainer Joswig wrote:
>>> This need to be 'superior' or 'better' is bullshit. A programming language
>>> is not just a bunch of technical features with 'objective'
>>> criteria to rank them.
>>> Programmer's needs and capabilities are vastly different.
>>> Programming languages are like a social eco-system. Plus
>>> there is human behavior engraved into our brains. For example
>>> people have the tendency to like what they already know. There
>>> is a hurdle to unlearn or relearn.
>> I totally agree.
>>
>>> I simply doubt we
>>> can judge whether Lisp is useful to somebody because we
>>> saw a cute macro example in some newsgroup.
>> Especially because macros - like any other metaprogramming approach -
>> only really pay off in large and complex systems, where it is worthwhile
>> to condense involved and longish code patterns into smaller units.
>>
>> 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/
 >
> Question: How does a large software project get to be one year late?
> Answer: One day at a time!
> Fred Brooks-The Mythical Man-Month
> 
> Metaprogramming pays very well in medium size projects also , beside
> condesing code, there is the utility syndrom. If you write something
> usefull you tend to use it, again and again and again.
> While ago I wrote a simple one liner called string+, and now I lost
> count how many  times I use it. It's contagious.

Yes, I forgot about better reuse of code patterns, which is also useful 
in small and medium-sized projects. Thanks for mentioning it.


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: ···············@gmail.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1190063800.721880.231450@g4g2000hsf.googlegroups.com>
On Sep 14, 6:31 am, Pascal Costanza <····@p-cos.net> wrote:
> Rainer Joswig wrote:
> ...
>
> > I simply doubt we
> > can judge whether Lisp is useful to somebody because we
> > saw a cute macro example in some newsgroup.
>
> Especially because macros - like any other metaprogramming approach -
> only really pay off in large and complex systems, where it is worthwhile
> to condense involved and longish code patterns into smaller units.
>

I think, in addition, one of the "problems" is that well-designed
macros look just like ordinary Common Lisp. To the person
inexperienced with CL, the gain from one CL code snippet without
macros to another CL code snippet using a "killer" macro is just not
obvious. Both look just as foreign.
From: Raffael Cavallaro
Subject: Re: A "killer" macro
Date: 
Message-ID: <2007091801123475249-raffaelcavallaro@pasdespamsilvousplaitmaccom>
On 2007-09-17 17:16:40 -0400, ················@gmail.com" 
<············@gmail.com> said:

> another CL code snippet using a "killer" macro is just not
> obvious. Both look just as foreign.

Killer macros usually have prison tats.
From: Wade Humeniuk
Subject: Re: A "killer" macro
Date: 
Message-ID: <m2r6l1nxye.fsf@telus.net.no.spam>
MY real answer, is ...  (BTW, Killer?? as in????)

1) Macros can be fun, I want programming to be enjoyable.

2) I can do things like create a macro at the heart of a a c++
   lexer that looks like

(in-package :archecode.c++)

;; The core lexer for C++, will break up C++ code into a sequence
;; of tokens. (complete with token start position, line and character)
(defun top-level-lexer (stream)
  (handler-case
      (lexer-loop (c stream top-level-lexer) ;; Here is the macro
        (member->loop (#\space #\tab #\newline #\cr #\ff))
        (c->loop #\# (lexdirective stream))
        (c->loop #\/ (lexcomment stream))
        (p->token start-symbol-char-p (lexback c stream) (lexsymbol stream))
        (backtrack-if-not (#\. digit-char-p) (lexnumber stream))
        (p->token digit-char-p (lexback c stream) (lexnumber stream))
        (c->token #\()
        (c->token #\))
        (c->token #\[)
        (c->token #\])
        (c->token #\{)
        (c->token #\})
        (c->token #\;)
        (c->token #\,)
        (c->token #\.)
        (c->token #\~)
        (ctree->token (#\: #\:))
        (ctree->token (#\+ #\+ #\=))
        (ctree->token (#\- #\- #\= #\>))
        (ctree->token (#\* #\=))
        (ctree->token (#\/ #\=))
        (ctree->token (#\% #\=))
        (ctree->token (#\> (#\> #\=) #\=))
        (ctree->token (#\< (#\< #\=) #\=))
        (ctree->token (#\& #\& #\=))
        (ctree->token (#\| #\| #\=))

ARCHECODE.C++ 9 > (with-input-from-string
                      (s "class test {
                          public:
                             test() {}
                             virtual ~test();
                          private:
                             int i;
                             void func1(int,float);
                          };")
                    (pprint (lex s)))

((|class| NIL 0 5)
 (%SYMBOL "test" 0 10)
 ({ NIL 0 12)
 (|public| NIL 1 45)
 (\: NIL 1 46)
 (%SYMBOL "test" 2 80)
 (\( NIL 2 81)
 (\) NIL 2 82)
 ({ NIL 2 84)
 (} NIL 2 85)
 (|virtual| NIL 3 122)
 (~ NIL 3 124)
 (%SYMBOL "test" 3 128)
 (\( NIL 3 129)
 (\) NIL 3 130)
 (\; NIL 3 131)
 (|private| NIL 4 165)
 (\: NIL 4 166)
 (|int| NIL 5 199)
 (%SYMBOL "i" 5 201)
 (\; NIL 5 202)
 (|void| NIL 6 236)
 (%SYMBOL "func1" 6 242)
 (\( NIL 6 243)
 (|int| NIL 6 246)
 (\, NIL 6 247)
 (|float| NIL 6 252)
 (\) NIL 6 253)
 (\; NIL 6 254)
 (} NIL 7 282)
 (\; NIL 7 283))
From: Marco Antoniotti
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189790111.744821.12420@d55g2000hsg.googlegroups.com>
Hi

this discussion has already presented many arguments on favor of
"killer macros", but here is a shameless plug. :)

CL-DEFINER in common-lisp.net.  You change the basic definition syntax
of CL, making it similar to Python and/or Ruby, while at the same time
being able to extend it as you wish.

The point is always the same.  You can write your own specialized
language in CL making it look like CL itself.  Sure you can hack
multimethods in Python (or maybe Ruby, I don't know) but to use them
you are not writing a Pythonesque language.  In order to actually
extend the syntax of Python or any other language, you need to hack
the parser.  The only other language that comes close to CL (or Scheme
or Dylan to a lesser extent, given their insistence on "hygiene") is
Prolog.  You can play trick with preprocessors elsewhere, like OCaml.
But the bottom line is that Lisp (CL) is like a ball of mud: it does
not matter how much mud you throw at it, it still looks like a ball of
mud (hence the not-so-necessary hygiene :) ).

Cheers

Marco



On Sep 12, 7:00 am, Eli Bendersky <······@gmail.com> wrote:
> On Sep 12, 10:28 am, Pascal Costanza <····@p-cos.net> wrote:
>
>
>
> > Eli Bendersky wrote:
> > > Hello all,
>
> > > In short: I'm looking for a "killer" macro - a macro (or a couple of
> > > related ones) that show what Lisp can do and other languages (those
> > > without uniform syntax) can not.
>
> > > A longer version: Many contemporary languages boast their sharing most
> > > of the functional features of Lisp. Perl, Ruby, Javascript - all have
> > > convenient lists (or arrays), functions as first class objects,
> > > garbage collection, dynamic typing, lexical closures. However, one
> > > thing they lack is uniform syntax, and hence the service of a powerful
> > > built-in macro system such as Common Lisp's "defmacro".
> > > When confronted by fellow programmers with the question "so why is
> > > Lisp so special", I'm looking for that short - not too hard to
> > > understand - snippet of code that will show them *why*. I'm convinced
> > > that such a snippet must involve macros. But all the examples I ran
> > > into so far have been either too simple - and could be easily
> > > implemented another way (for example with Ruby's blocks), or too
> > > complicated.
>
> > > Any suggestions for such an example ?
>
> > Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
>
> Pascal, this can be achieved in Ruby in a simpler way, so it won't
> cut.
>
> I think that the direction should be towards some brilliant example of
> a simple DSL that looks like any other Lisp code. *this* can't be done
> in a non-uniform syntax language.
>
> Eli
From: ···············@gmail.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189605548.243583.100060@g4g2000hsf.googlegroups.com>
On Sep 12, 9:28 am, Pascal Costanza <····@p-cos.net> wrote:
> Eli Bendersky wrote:
> > In short: I'm looking for a "killer" macro - a macro (or a
> > Any suggestions for such an example ?
>
> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html

Over the last few months I've shown Pascal's example to a few of my
skeptical colleagues and have had a reasonable success rate (no actual
converts but certainly some curiosity). I think the examples are good
because they're short and in my experience, when advocating a
programming language, you have about 60 seconds to hook someone before
they return to Eclipse.

I suspect these examples work best on Java and C# programmers as these
languages provide the least support for this way of thinking. The more
dynamic languages all have their own approximations which make the
examples seem less impressive. But perhaps Ruby, Python and Smalltalk
programmers can better appreciate a longer DSL-style example.

--
Phil
http://phil.nullable.eu/
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kv5rnF5jsceU1@mid.individual.net>
···············@gmail.com wrote:
> On Sep 12, 9:28 am, Pascal Costanza <····@p-cos.net> wrote:
>> Eli Bendersky wrote:
>>> In short: I'm looking for a "killer" macro - a macro (or a
>>> Any suggestions for such an example ?
>> Here is my best attempt so far:http://p-cos.blogspot.com/2007/02/what-is-point-of-macros.html
> 
> Over the last few months I've shown Pascal's example to a few of my
> skeptical colleagues and have had a reasonable success rate (no actual
> converts but certainly some curiosity). I think the examples are good
> because they're short and in my experience, when advocating a
> programming language, you have about 60 seconds to hook someone before
> they return to Eclipse.
> 
> I suspect these examples work best on Java and C# programmers as these
> languages provide the least support for this way of thinking.

That's no surprise, because I come from a Java background.

> The more
> dynamic languages all have their own approximations which make the
> examples seem less impressive. But perhaps Ruby, Python and Smalltalk
> programmers can better appreciate a longer DSL-style example.

A couple of months ago, I had a discussion with Robert Hirschfeld, who I 
collaborate with on context-oriented programming. While I am working on 
ContextL for Common Lisp, he implements something very similar for 
Smalltalk/Squeak.

I was a little bit puzzled by his design. While in ContextL, you can say 
something like this:

(with-active-layers (layer1 layer2)
   ... some code ...)

In ContextS, you have to say the same thing as follows:

[ {Layer1 new, Layer2 new} ]
   useAsLayersFor: [ ... some code ...]

While I understand that it's natural in Smalltalk to use blocks for 
delaying evaluation of code, I wondered why he puts the layers first and 
uses a relatively weird name for layer activation, instead of putting 
something like withActiveLayers in front and passing two arguments to it.

What I hadn't realized: In Smalltalk, it's actually impossible to add 
any new constructs other than by declaring new methods. Such new methods 
always require a message send to some object. There is no way to add 
plain function calls, lest to speak any macros. There are also no 
implicit self sends with which you could fake this.

I guess, I would try to come up with an example where I add a new 
language construct that doesn't require a target object for a message 
send, if I were to try to illustrate the benefits of macros to a 
Smalltalker. (But then again, plain functions would already be 
beneficial here...)


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: ···············@gmail.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189803490.381568.73800@d55g2000hsg.googlegroups.com>
Pascal Costanza wrote:

> A couple of months ago, I had a discussion with Robert Hirschfeld, who I
> collaborate with on context-oriented programming. While I am working on
> ContextL for Common Lisp, he implements something very similar for
> Smalltalk/Squeak.

> What I hadn't realized: In Smalltalk, it's actually impossible to add
> any new constructs other than by declaring new methods.

I've grown increasingly skeptical of languages with a single paradigm
and no extensibility. I guess these languages are easier to teach and
understand but I'm bemused when people invest so much effort in
extending them rather than choosing a language with the necessary join
points to do it properly.

--
Phil
http://phil.nullable.eu/
From: Ken Tilton
Subject: Re: A "killer" macro
Date: 
Message-ID: <eQSFi.1561$Z%7.948@newsfe12.lga>
Eli Bendersky wrote:
> Hello all,
> 
> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.

Search c.l.lisp,c.l.python a coupla years back for a thread on why 
Python should macros in which I offer DEFGOAL (or something like that) 
from my RoboCup effort, called variously RoboCells and TeamKenny.

kt

-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: Thomas A. Russ
Subject: Re: A "killer" macro
Date: 
Message-ID: <ymiodg7agn5.fsf@blackcat.isi.edu>
Eli Bendersky <······@gmail.com> writes:

> Hello all,
> 
> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.

Well, one nice, small example that I like is:

  WITH-OPEN-FILE

which actually doesn't really depend all that much on uniform syntax,
but more on just being able to wrap arbitrary code around something
else.  This illustrates the ability to build structures to do clean-up.
Now, some C++ aficionados will point to destructors as a way to do
that.  The reply there is to ask how one would have added a feature like
that to the language as a programmer?  In lisp you can do it.

If you want to do something more web-ish, then perhaps a simple HTML
generation example would do.  It also can illustrate some of the
processing features being able to program the macro can do.  Something
like the following (omitting the ONCE-ONLY or GENSYM treatment for
clarity):

(defmacro with-html-tag ((stream tag &rest attribute-value-pairs)
                          &body body)
  `(progn
      (format ,stream "<~a~{ ~a='~a'~}" ,tag ,attribute-value-pairs)
      ,(if (null body)
           `(format ,stream "/>")
           `(format ,stream ">"))
      ,@body
      ,@(when body `((format ,stream "</~a>" tag)))))

  (with-html-tag (web-response-stream "H1")
     (compute-and-print-title-for-this-page web-response-stream))

  (with-html-tag (*standard-output* "FONT" "COLOR" "#FF0000")
    (with-html-tag (*standard-output* "B")
      (with-html-tag (*standard-output "I")
         (write-string "This is great!"))))

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189675541.947247.327380@50g2000hsm.googlegroups.com>
On Sep 12, 8:21 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> Eli Bendersky <······@gmail.com> writes:
> > Hello all,
>
> > In short: I'm looking for a "killer" macro - a macro (or a couple of
> > related ones) that show what Lisp can do and other languages (those
> > without uniform syntax) can not.
>
> Well, one nice, small example that I like is:
>
>   WITH-OPEN-FILE
>
> which actually doesn't really depend all that much on uniform syntax,
> but more on just being able to wrap arbitrary code around something
> else.  This illustrates the ability to build structures to do clean-up.
> Now, some C++ aficionados will point to destructors as a way to do
> that.  The reply there is to ask how one would have added a feature like
> that to the language as a programmer?  In lisp you can do it.
>
> If you want to do something more web-ish, then perhaps a simple HTML
> generation example would do.  It also can illustrate some of the
> processing features being able to program the macro can do.  Something
> like the following (omitting the ONCE-ONLY or GENSYM treatment for
> clarity):
>
> (defmacro with-html-tag ((stream tag &rest attribute-value-pairs)
>                           &body body)
>   `(progn
>       (format ,stream "<~a~{ ~a='~a'~}" ,tag ,attribute-value-pairs)
>       ,(if (null body)
>            `(format ,stream "/>")
>            `(format ,stream ">"))
>       ,@body
>       ,@(when body `((format ,stream "</~a>" tag)))))
>
>   (with-html-tag (web-response-stream "H1")
>      (compute-and-print-title-for-this-page web-response-stream))
>
>   (with-html-tag (*standard-output* "FONT" "COLOR" "#FF0000")
>     (with-html-tag (*standard-output* "B")
>       (with-html-tag (*standard-output "I")
>          (write-string "This is great!"))))
>

While these are nice macros, they're just a way to hide the lambdas,
and Ruby has a built in syntax for such things, so it's not too
convincing.

Eli
From: Alex Mizrahi
Subject: Re: A "killer" macro
Date: 
Message-ID: <46e7d30c$0$90267$14726298@news.sunsite.dk>
(message (Hello 'Eli)
(you :wrote  :on '(Wed, 12 Sep 2007 06:59:19 -0000))
(

 EB> understand - snippet of code that will show them *why*. I'm convinced
 EB> that such a snippet must involve macros. But all the examples I ran
 EB> into so far have been either too simple - and could be easily
 EB> implemented another way (for example with Ruby's blocks), or too
 EB> complicated.

 EB> Any suggestions for such an example ?

well, best of my personal achievements so far is a macro for RDF queries, 
that automatically creates kinda SPARQL query, binding lexical variables 
wherever needed, executes it and binds result to lexical variables. i've 
shown it to some haskellist once, and he had to admit that such DSL in 
Haskell will either have freaky syntax/semantics, or that would be external 
DSL.
as a bonus of using embedded DSL i can use it togerther with HTML generation 
macros:

(:p
     (:table
      (:tr (:th "username") (:th "department") (:th "salary"))
      (rdf-do-query
       ((?user :username ?uname)
        (?user :salary ?salary)
        (?user :department ?dept)
        (?dept :name ?dept-name))
       (html
        (:tr
         (:td (:princ ?uname))
         (:td (:princ ?dept-name))
         (:td (:princ ?salary)))))))

if you'd like some more details i can provide them.
afair there were some libraries that can express SQL in a lispy notation and 
well integrated -- something called Uncommon SQL or whatever..pretty 
impressive too, IMO.

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"i've killed myself i've been born again") 
From: Dimiter "malkia" Stanev
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kr6aeF55scfU1@mid.individual.net>
For a code that was doing LZO decompression, I've added the following 
macros, that were "simulating" how for example "*p++ = value", or "*p++ 
= *x++", or memcpy(). Granted not the best macros, but minimized my code.

(defmacro aref++ (array index)
   "Does the same job aref does, but increases index after that"
   `(aref ,array (prog1 ,index (incf ,index))))

(defmacro acpy++1 (dst dst-index src src-index)
   `(setf (aref++ ,dst ,dst-index)
          (aref++ ,src ,src-index)))

(defmacro acpy++ (dst dst-index src src-index times)
   (if (constantp times)
     (let ((code))
       (dotimes (ignored times)
         (push `(acpy++1 ,dst ,dst-index ,src ,src-index) code))
       (push 'progn code)
       code)
     `(dotimes (ignored ,times)
        (acpy++1 ,dst ,dst-index ,src ,src-index))))

Here is an example of how to use them

The following would copy 15 bytes from the source-array starting from 
the source-index, in the dest-array, starting from the dest-index. It 
would then increase dest-index and source-index by 15.

    (acpy++ dest-array dest-index source-array source-index 15)

Also note that this would check whether the number of indexes is 
constant, and in the case above it is (15), so it would actually unroll 
that, instead of loop it.

Thanks,
Dimiter "malkia" Stanev.
From: Madhu
Subject: Re: A "killer" macro
Date: 
Message-ID: <m3odg79jpq.fsf@robolove.meer.net>
Helu

* "Dimiter <······@gmail.com> <··············@mid.individual.net> :

| For a code that was doing LZO decompression, I've added the following
| macros, that were "simulating" how for example "*p++ = value", or
| "*p++ = *x++", or memcpy(). Granted not the best macros, but minimized
| my code.
|
<SNIP>
| Here is an example of how to use them
|
| The following would copy 15 bytes from the source-array starting from
| the source-index, in the dest-array, starting from the dest-index. It
| would then increase dest-index and source-index by 15.
|
|    (acpy++ dest-array dest-index source-array source-index 15)

Just FYI that should equivalent to

(replace dest-array source-array :start1 dest-index :start2
	:source-index :end2 (+ source-index 15))

or using a macro:
(setf (subseq dest-array dest-index)
      (subseq source-array source-index (+ source-index 15)))

[untested]

| Also note that this would check whether the number of indexes is
| constant, and in the case above it is (15), so it would actually
| unroll that, instead of loop it.
--
Madhu
From: ··············@yahoo.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189667071.714251.192030@o80g2000hse.googlegroups.com>
I was asked a while back to code up a poker simulation for a project.
I did this in Smalltalk, which was quite a nice language for a
programmer to work in, especially for this type of problem, and I was
able to do the work much easier, quicker, and with much less headache
than in a "conventional" language - say Java (barf).

However, upon reevaluating the solution and reflecting on it, I saw
where another language could have done "the core" of the program (hand
evaluation) much better, and in much less length of code, with far
less possibility (none) of bugs.  This language was Prolog.  I re-
implemented "the core" in Prolog, and got at least a 20-1 reduction in
the size of the code there.  In fact, all the code for "the core"
could fit on one page of Prolog.  Better still, when I ran the new
code against the old code for the same inputs (given 7 cards,
evaluate, and return the best 5 card hand), it "disagreed" with the
old code on about 5 hands out of several million randomly generated
hands, and spit out different solutions for those hands.  When I
analyzed the differences, I found that the Prolog solution was correct
in those cases.  It was due to a few hard-to-find bugs in the old
solution, which was to be expected simply because that code was much
longer and more complex.  So the new Prolog solution, because of its
simplicity, was also more correct, and uncovered bugs in the old
solution.

To illustrate the conciseness of the Prolog solution, here is the code
to recognize a "4 of a kind":

quad(A,B,C,D,E,F,G) :- permutation([A,B,C,D,E,F,G],[X,X,X,X,_,_,_]).

That's it - one line of code, and the input doesn't even need to be
sorted beforehand, as the old solution's input did, so I get to remove
an unnecessary sort.

At any rate, if I didn't know Prolog, and if someone showed me this
solution as compared with my old solution, I'd be quite impressed -
impressed enough to learn Prolog right away, or at least look at it.
The point being, I am impressed with a language if it provides for
solving problems in as short a length of code as possible, with the
least amount of complexity as possible, while still being completely
readable, intuitive, understandable, bug-free and correct.  1 line of
code beats a page or several pages of code any day.

APL (and its successor - J) has a reputation for being able to produce
amazingly short solutions for some problems.  I saw a one line APL
program for Conway's Game of Life.  The problem I have with APL (and
J) is the "while still being completely readable" element I mentioned
above.

Anyway, the point:  Can you find an example of being able to do
something in Lisp in 1) much shorter length of code, AND/OR 2) much
less complexity, than many "conventional" languages could do it?
Perhaps the best way to prune the list of possible things to examine
is to first think about those couple of things about Lisp that are
particularly strong, or make it stand out, or make it different than
other languages, and then look for classes of problems which those
strengths/differences can be applied.  For instance, with Prolog, its
strengths and differences are pattern-matching, unification, and
backtracking.  With the above solution, it doesn't even use its stand-
out feature of backtracking - it's simply all pattern-matching/
unification.  For APL/J, it excels at doing array/matrix operations in
parallel, with no need for explicit looping constructs.

Lisp excels at _____ (fill in the blank).  Now you've at least
eliminated some possibilities in your search.

(Maybe you already filled-in the blank with this macro capability you
spoke of.  However, if it is difficult to find something here dramatic
enough to impress your friends, perhaps you can list other Lisp
"standout" features?  Or perhaps Lisp doesn't have one thing ultra-
dramatic in one particular category, but a lot of less dramatic things
in many categories, and these things all add up in the end?  If
nothing else, at least Lisp's syntax isn't nearly as grotesque and
burdensome as something like Java's.  Come on - look at a Java "Hello
World" program, with the class declaration, the "public static void
main," the "System.blah.whatever.printblah" hideousness, etc. - but
then again if it hasn't already occurred to a Java programmer to hate
all of that stuff, you are probably barking up the wrong tree with
trying to convert that particular person.)

Regards.
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189675849.006869.263540@19g2000hsx.googlegroups.com>
> Lisp excels at _____ (fill in the blank).  Now you've at least
> eliminated some possibilities in your search.
>
> (Maybe you already filled-in the blank with this macro capability you
> spoke of.  However, if it is difficult to find something here dramatic
> enough to impress your friends, perhaps you can list other Lisp
> "standout" features?  Or perhaps Lisp doesn't have one thing ultra-
> dramatic in one particular category, but a lot of less dramatic things
> in many categories, and these things all add up in the end?  If
> nothing else, at least Lisp's syntax isn't nearly as grotesque and
> burdensome as something like Java's.  Come on - look at a Java "Hello
> World" program, with the class declaration, the "public static void
> main," the "System.blah.whatever.printblah" hideousness, etc. - but
> then again if it hasn't already occurred to a Java programmer to hate
> all of that stuff, you are probably barking up the wrong tree with
> trying to convert that particular person.)
>
> Regards.

But you see, as I mentioned in my original post, Lisp really stands
out only in its macros, because all the rest was already implemented
in other languages. Yes, 20 years ago Lisp was amazing - compared with
C, Fortran and Pascal, but these days with Perl, Ruby and even C# 3.0
around, the only thing that *really* sets Lisp apart is macros.

Eli
From: Rainer Joswig
Subject: Re: A "killer" macro
Date: 
Message-ID: <joswig-C9ADEE.12342013092007@news-europe.giganews.com>
In article <························@19g2000hsx.googlegroups.com>,
 Eli Bendersky <······@gmail.com> wrote:

> > Lisp excels at _____ (fill in the blank).  Now you've at least
> > eliminated some possibilities in your search.
> >
> > (Maybe you already filled-in the blank with this macro capability you
> > spoke of.  However, if it is difficult to find something here dramatic
> > enough to impress your friends, perhaps you can list other Lisp
> > "standout" features?  Or perhaps Lisp doesn't have one thing ultra-
> > dramatic in one particular category, but a lot of less dramatic things
> > in many categories, and these things all add up in the end?  If
> > nothing else, at least Lisp's syntax isn't nearly as grotesque and
> > burdensome as something like Java's.  Come on - look at a Java "Hello
> > World" program, with the class declaration, the "public static void
> > main," the "System.blah.whatever.printblah" hideousness, etc. - but
> > then again if it hasn't already occurred to a Java programmer to hate
> > all of that stuff, you are probably barking up the wrong tree with
> > trying to convert that particular person.)
> >
> > Regards.
> 
> But you see, as I mentioned in my original post, Lisp really stands
> out only in its macros, because all the rest was already implemented
> in other languages.

Unfortunately in hundreds of languages. In Lisp you can have
it in one language.

Sure with XML now everybody can describe data (and even procedures)
with a prefix language. Unfortunately the mechanisms are
ugly, monstrous and much less integrated.

In Lisp I write

(service-call "SVCL"
  (04 18 customer-name)
  (19 23 customer-id)
  (24 27 call-type-code)
  (28 35 date-of-call-string))

and READ reads it. Plain and simple. No monstrous XML
parser. If I want to do something with it I apply
a function. If I want to compile it with the compiler
to some efficient procedure, I write a macro and
add it to the expression:

(DEFMAPPING service-call "SVCL"
  (04 18 customer-name)
  (19 23 customer-id)
  (24 27 call-type-code)
  (28 35 date-of-call-string))

Still I'm able to READ it, pretty print it, transform it.
All with mildly simple mechanisms.

> Yes, 20 years ago Lisp was amazing - compared with
> C, Fortran and Pascal, but these days with Perl, Ruby and even C# 3.0
> around, the only thing that *really* sets Lisp apart is macros.
> 
> Eli

That's plain wrong.

Macros are available in other programming languages, too.

Common Lisp is a multi-paradigm language that enables
interactive software development of small to very
large programs with somehow useful efficiency.
At its core it is very extensible to be able to
add very different programming paradigms.

PERL, Ruby and C# are very different. In Common Lisp
you can do most that those can in one package.
Ruby is totally inefficient (besides what is implemented
in C in its core) and there is little hope that it
can be better. You can write most Ruby stuff relatively
easy in Lisp, but if you try to use Ruby for Lisp
software be prepared for a hard time.
C# is a static language in the
tradition of C, C++ and others with more complication
bolted on the totally wrong base language. Sure
you can have closures in C#, but the result is ugly.
I you bolt wings on Frankenstein's monster, do you
think it will be a beautiful bird?

I try to minimize my writing of macros, that's not the single
important feature for me. I have not found
any environment for Ruby, Perl or C# that works
like Allegro CL, MCL, LispWorks or even Symbolics Genera.
The only ones that are close are Smalltalk environments
and some less known others.

-- 
http://lispm.dyndns.org
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189693822.379895.81840@g4g2000hsf.googlegroups.com>
On Sep 13, 12:34 pm, Rainer Joswig <······@lisp.de> wrote:
> In article <························@19g2000hsx.googlegroups.com>,
>  Eli Bendersky <······@gmail.com> wrote:
>
>
>
> > > Lisp excels at _____ (fill in the blank).  Now you've at least
> > > eliminated some possibilities in your search.
>
> > > (Maybe you already filled-in the blank with this macro capability you
> > > spoke of.  However, if it is difficult to find something here dramatic
> > > enough to impress your friends, perhaps you can list other Lisp
> > > "standout" features?  Or perhaps Lisp doesn't have one thing ultra-
> > > dramatic in one particular category, but a lot of less dramatic things
> > > in many categories, and these things all add up in the end?  If
> > > nothing else, at least Lisp's syntax isn't nearly as grotesque and
> > > burdensome as something like Java's.  Come on - look at a Java "Hello
> > > World" program, with the class declaration, the "public static void
> > > main," the "System.blah.whatever.printblah" hideousness, etc. - but
> > > then again if it hasn't already occurred to a Java programmer to hate
> > > all of that stuff, you are probably barking up the wrong tree with
> > > trying to convert that particular person.)
>
> > > Regards.
>
> > But you see, as I mentioned in my original post, Lisp really stands
> > out only in its macros, because all the rest was already implemented
> > in other languages.
>
> Unfortunately in hundreds of languages. In Lisp you can have
> it in one language.
>

This is a good point. But it's true because of macros. With macros and
Lisp's uniform syntax, I can not only write a library that implements
anything I might deem important, but also make it look
indistinguishable from native Lisp - extend the language itself.

> Sure with XML now everybody can describe data (and even procedures)
> with a prefix language. Unfortunately the mechanisms are
> ugly, monstrous and much less integrated.
>
> In Lisp I write
>
> (service-call "SVCL"
>   (04 18 customer-name)
>   (19 23 customer-id)
>   (24 27 call-type-code)
>   (28 35 date-of-call-string))
>
> and READ reads it. Plain and simple. No monstrous XML
> parser. If I want to do something with it I apply
> a function. If I want to compile it with the compiler
> to some efficient procedure, I write a macro and
> add it to the expression:
>
> (DEFMAPPING service-call "SVCL"
>   (04 18 customer-name)
>   (19 23 customer-id)
>   (24 27 call-type-code)
>   (28 35 date-of-call-string))
>
> Still I'm able to READ it, pretty print it, transform it.
> All with mildly simple mechanisms.

Yes, but this already exists in other languages. Javascript has JSON
which is almost like the Lisp way of storing data in s-expressions.
YAML is also popular (and 99% equivalent to JSON).

>
> > Yes, 20 years ago Lisp was amazing - compared with
> > C, Fortran and Pascal, but these days with Perl, Ruby and even C# 3.0
> > around, the only thing that *really* sets Lisp apart is macros.
>
> > Eli
>
> That's plain wrong.
>
> Macros are available in other programming languages, too.
>
> Common Lisp is a multi-paradigm language that enables
> interactive software development of small to very
> large programs with somehow useful efficiency.
> At its core it is very extensible to be able to
> add very different programming paradigms.
>

Yes, true - "at its core it is very extensible" *because* of macros.

> PERL, Ruby and C# are very different. In Common Lisp
> you can do most that those can in one package.
> Ruby is totally inefficient (besides what is implemented
> in C in its core) and there is little hope that it
> can be better. You can write most Ruby stuff relatively
> easy in Lisp, but if you try to use Ruby for Lisp
> software be prepared for a hard time.

Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
has except macros. Ruby is the latest and greatest in the evolution
path of modern programming languages and their convergence path with
Lisp. Again, I'll use Norvig's "seven points that make Lisp
different".

Ruby:

* It has a convenient built-in syntax for arrays and hash tables
* Garbage collection
* Dynamic typing - in fact the closest to Lisp yet (except maybe
Smalltalk, with which I'm not familiar) with its duck typing
philosophy
* First class functions, with the syntactic sugar called "blocks"
which makes a lot of higher-order functional paradigms very convenient
* Interactive Environment - Ruby's "irb" is in many ways equivalent to
the REPL. And Ruby slowly but surely gets the support of good IDEs -
Emacs, Eclipse, Visual Studio, NetBeans and so on.
* Extensibility - everything is modifiable, full reflection
capabilities - you can even change built-in classes on the fly.
module_eval and class_eval allow for much safer code generation than
the string eval of Perl. Ruby is open enough to be the most convenient
language, after Lisp of course, for writing DSLs.

* Uniform syntax: Bzzzzt! Nope. None, and so no *real* macros either.
Ruby loses to Lisp on this point, and this is a big point,
admittedly.

But when you tell people about this last point, they say - fine, but
what's so great about these macros.
And so we come back to the original reason for my starting this
thread!

Eli




[1] I see no reason why Ruby should be inherently less efficient than
any other interpreted language. With its new VM in development, it has
hope yet. And anyway, performance alone can't play that big a role.
Ruby's interoperability with C is much simpler to work out than CL's
CFFI, and writing critical code in C is very possible.
From: ···············@gmail.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189696279.080495.247510@22g2000hsm.googlegroups.com>
On Sep 13, 3:30 pm, Eli Bendersky <······@gmail.com> wrote:
> On Sep 13, 12:34 pm, Rainer Joswig <······@lisp.de> wrote:

> But when you tell people about this last point, they say - fine, but
> what's so great about these macros.
> And so we come back to the original reason for my starting this
> thread!

[Rainer has already explained this very eloquently but I'll have
another go...]

I use macros fairly infrequently but when I do use them, I feel
they're the best solution to the problem I'm trying to tackle. But
Common Lisp is more than just macros just as Ruby is more than just
Rails and Python is more than just funny indentation rules. After
working in many different languages over the years, Lisp offers me the
most choices all contained in a pretty consistent whole. This is the
beauty of the language. Macros are but one part of that.

--
Phil
http://phil.nullable.eu/
From: jayessay
Subject: Re: A "killer" macro
Date: 
Message-ID: <m3k5qu1lo7.fsf@sirius.goldenthreadtech.com>
Eli Bendersky <······@gmail.com> writes:

...

> Ruby is the latest and greatest in the evolution path of modern
> programming languages

I wonder how many people actually believe this...


> Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
> has except macros. ...  Again, I'll use Norvig's "seven points that
> make Lisp different".

These "seven points" miss some things.  And at least one isn't even
true.  A couple things missing from the seven points and from things
like Ruby:

* Condition system and what it can do.

* CLOS.  In particular, the concept of generic functions (as
  orthogonal to class structure) and multiple dispatch.  Generic
  functions are really what "OO" should be about.

* MOP.

Also the "Extensibility" point, as stated, is obviously false:
"everything is modifiable".  Clearly the language itself isn't - for
example you can't change things like method dispatch.  And you can't
add/change syntactic constructs.  Sure, this is where you claim the
"uniform syntax" comes in, but really, that is an _enabler_ not the
actual point.


> [1] I see no reason why Ruby should be inherently less efficient than
> any other interpreted language.

Probably it can be reasonably compiled - but it isn't.  And Lisp
systems have had large amounts of effort put into compilation
techniques for highly efficient code generation by extremely smart
folks for decades.  It's hard to match that w/o comparable effort and
time frames...


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Ken Tilton
Subject: Re: A "killer" macro
Date: 
Message-ID: <x6gGi.47$%37.23@newsfe12.lga>
jayessay wrote:
> Eli Bendersky <······@gmail.com> writes:
> 
> ...
> 
> 
>>Ruby is the latest and greatest in the evolution path of modern
>>programming languages

Yep, it actually leads Python on Google Fight, 97.8m to 79.8m. Wish I 
had been keeping track, Python was way ahead not too long ago.

The bad news for Ruby is that it's reign will be just long enough for 
O'Reilly to get stuck with a lot of Ruby inventory, Lisp is coming up 
fast like a thorobred on a herd of donkeys at 25m.

The neat thing is that, as far as I can make out, Russell produced that 
first working interpreter early in '59, with work on the implementation 
having begun in late '58. We will be smack on top of the golden 
anniversary when Lisp moves into first place to stay.

kt


-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: jayessay
Subject: Re: A "killer" macro
Date: 
Message-ID: <m3fy1i17j7.fsf@sirius.goldenthreadtech.com>
Ken Tilton <···········@optonline.net> writes:

> jayessay wrote:
> > Eli Bendersky <······@gmail.com> writes:
> > ...
> >
> >>Ruby is the latest and greatest in the evolution path of modern
> >>programming languages

Hey, I didn't write that nonsense.


> Yep, it actually leads Python on Google Fight, 97.8m to 79.8m. Wish I
> had been keeping track, Python was way ahead not too long ago.

And this has nothing to do with the (admitted value judgement) claim
that it is the "latest and greatest int the evolution [sic] path".
That is, Google fight is at best a "metric" (bad as it is) of
_popularity_; not "lateness" "greatness" or "evolutionary" aspects.


> The bad news for Ruby is that it's reign will be just long enough
> for O'Reilly to get stuck with a lot of Ruby inventory, Lisp is
> coming up fast like a thorobred on a herd of donkeys at 25m.

That's probably just a blip - their likely still making out very well
on their crappy Java books.


> The neat thing is that, as far as I can make out, Russell produced
> that first working interpreter early in '59, with work on the
> implementation having begun in late '58. We will be smack on top of
> the golden anniversary when Lisp moves into first place to stay.

Well, we can hope - but I wouldn't hold my breath ...


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189750351.093714.303020@r29g2000hsg.googlegroups.com>
> > Ruby is the latest and greatest in the evolution path of modern
> > programming languages
>
> I wonder how many people actually believe this...

Unfortunately for Lisp, about 100 times as much as the total amount of
CL users.

>
> > Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
> > has except macros. ...  Again, I'll use Norvig's "seven points that
> > make Lisp different".
>
> These "seven points" miss some things.  And at least one isn't even
> true.  A couple things missing from the seven points and from things
> like Ruby:
>
> * Condition system and what it can do.
>

What can it do, indeed ? This is meant as an innocent question. Can
you explain in a couple of sentences how CL's condition system is
better than Ruby's exception handling ?

> * CLOS.  In particular, the concept of generic functions (as
>   orthogonal to class structure) and multiple dispatch.  Generic
>   functions are really what "OO" should be about.
>

Yes, and on the other hand many known Lispers (PG, for example) claim
that Lisp is "above" OO.

> * MOP.

Hmm... I think Ruby has this.

Eli
From: Ken Tilton
Subject: Re: A "killer" macro
Date: 
Message-ID: <1ZuGi.3$_M3.2@newsfe12.lga>
Eli Bendersky wrote:
>>>Ruby is the latest and greatest in the evolution path of modern
>>>programming languages
>>
>>I wonder how many people actually believe this...
> 
> 
> Unfortunately for Lisp, about 100 times as much as the total amount of
> CL users.

Unfortunate? Oh yes. I swung by the monastery the other day and the 
monks were crying in their twig teas about all the people down at the 
football stadium. I suggested tailgate parties, wet T-shirt contests, 
and Monday Night Sitting. They liked it, we're talking to NPR about 
broadcast rights.

kenny

-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: jayessay
Subject: Re: A "killer" macro
Date: 
Message-ID: <m37imt1d08.fsf@sirius.goldenthreadtech.com>
Ken Tilton <···········@optonline.net> writes:

> Eli Bendersky wrote:
> >>>Ruby is the latest and greatest in the evolution path of modern
> >>>programming languages
> >>
> >>I wonder how many people actually believe this...
> > Unfortunately for Lisp, about 100 times as much as the total amount
> > of
> > CL users.
> 
> Unfortunate? Oh yes. I swung by the monastery the other day and the
> monks were crying in their twig teas about all the people down at the
> football stadium. I suggested tailgate parties, wet T-shirt contests,
> and Monday Night Sitting. They liked it, we're talking to NPR about
> broadcast rights.

This is _vastly_ better than my reply on this comment.  I guess that's
why you are "Your Kennyness"...


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kuoc7F5mgi7U1@mid.individual.net>
Eli Bendersky wrote:
>>> Ruby is the latest and greatest in the evolution path of modern
>>> programming languages
>> I wonder how many people actually believe this...
> 
> Unfortunately for Lisp, about 100 times as much as the total amount of
> CL users.
> 
>>> Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
>>> has except macros. ...  Again, I'll use Norvig's "seven points that
>>> make Lisp different".
>> These "seven points" miss some things.  And at least one isn't even
>> true.  A couple things missing from the seven points and from things
>> like Ruby:
>>
>> * Condition system and what it can do.
>>
> 
> What can it do, indeed ? This is meant as an innocent question. Can
> you explain in a couple of sentences how CL's condition system is
> better than Ruby's exception handling ?
> 
>> * CLOS.  In particular, the concept of generic functions (as
>>   orthogonal to class structure) and multiple dispatch.  Generic
>>   functions are really what "OO" should be about.
>>
> 
> Yes, and on the other hand many known Lispers (PG, for example) claim
> that Lisp is "above" OO.
> 
>> * MOP.
> 
> Hmm... I think Ruby has this.

No, not really.

When do you start to form your own opinions?


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: Rainer Joswig
Subject: Re: A "killer" macro
Date: 
Message-ID: <joswig-7F1A24.08555014092007@news-europe.giganews.com>
In article <························@r29g2000hsg.googlegroups.com>,
 Eli Bendersky <······@gmail.com> wrote:

> > > Ruby is the latest and greatest in the evolution path of modern
> > > programming languages
> >
> > I wonder how many people actually believe this...
> 
> Unfortunately for Lisp, about 100 times as much as the total amount of
> CL users.
> 
> >
> > > Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
> > > has except macros. ...  Again, I'll use Norvig's "seven points that
> > > make Lisp different".
> >
> > These "seven points" miss some things.  And at least one isn't even
> > true.  A couple things missing from the seven points and from things
> > like Ruby:
> >
> > * Condition system and what it can do.
> >
> 
> What can it do, indeed ? This is meant as an innocent question. Can
> you explain in a couple of sentences how CL's condition system is
> better than Ruby's exception handling ?

Common Lisp has a model where on error there is
* a look-up for a matching handler
* the handler found is being called
* the handler can look for restarts and pick one

Note that the handler is called. In many other exception systems
there is a 'jump' to the handler and this is unwinding the stack.
In CL this means one can for example fix the error and just
continue at the exact place.

For example see this usage of ASSERT. ASSERT checks the first form.
If it fails you can reset the list of places we have mentioned
and continue.
The check will be done again. Until we have the form returning
non-nil. 

Welcome to OpenMCL Version 1.0-rc1-050922 (DarwinPPC32)!
? (defun foo (a)
     ; let's check that a is odd
     (assert (oddp a) (a) "A=~a is even, make it odd" a)
     ; we reach here only if a is really odd
     (+ a 1))          
FOO
? (foo 2)
> Error in process listener(1): A=2 is even, make it odd
> While executing: CCL::%ASSERTION-FAILURE
> Type :GO to continue, :POP to abort.
> If continued: allow some places to be set and test the assertion again.
Type :? for other options.
1 > (continue)
Type expressions to set places to, or nothing to leave them alone.
Value for A: 2
> Error in process listener(1): A=2 is even, make it odd
> While executing: CCL::%ASSERTION-FAILURE
> Type :GO to continue, :POP to abort.
> If continued: allow some places to be set and test the assertion again.
Type :? for other options.
1 > (continue)
Type expressions to set places to, or nothing to leave them alone.
Value for A: 3
4

There are many others uses of resumable exceptions.

> 
> > * CLOS.  In particular, the concept of generic functions (as
> >   orthogonal to class structure) and multiple dispatch.  Generic
> >   functions are really what "OO" should be about.
> >
> 
> Yes, and on the other hand many known Lispers (PG, for example) claim
> that Lisp is "above" OO.
> 
> > * MOP.
> 
> Hmm... I think Ruby has this.

Partly.

http://lispm.dyndns.org/documentation/amop/toc.html

> 
> Eli
From: jayessay
Subject: Re: A "killer" macro
Date: 
Message-ID: <m3bqc51d5v.fsf@sirius.goldenthreadtech.com>
Eli Bendersky <······@gmail.com> writes:

> > > Ruby is the latest and greatest in the evolution path of modern
> > > programming languages
> >
> > I wonder how many people actually believe this...
> 
> Unfortunately for Lisp, about 100 times as much as the total amount of
> CL users.

Why is it "unfortunate"?  Doesn't seem to matter at all one way or the
other.


> > * Condition system and what it can do.
> >
> 
> What can it do, indeed ? This is meant as an innocent question. Can
> you explain in a couple of sentences how CL's condition system is
> better than Ruby's exception handling ?

I don't spend much time on this sort of "task".  Here's one sentence,
which you should then use as a prod to check it out further:
Exceptions are a proper subset of conditions.


> > * CLOS.  In particular, the concept of generic functions (as
> >   orthogonal to class structure) and multiple dispatch.  Generic
> >   functions are really what "OO" should be about.
> >
> 
> Yes, and on the other hand many known Lispers (PG, for example) claim
> that Lisp is "above" OO.

Irrelevant.  The point stands.  And BTW, PG doesn't make this claim,
he merely claims OO is ill defined and highly overrated.

> > * MOP.
> 
> Hmm... I think Ruby has this.

You should try to think harder.  If you accept the CLOS claim, you
should realize that the MOP claim is significantly stronger.


/Jon

-- 
'j' - a n t h o n y at romeo/charley/november com
From: Rainer Joswig
Subject: Re: A "killer" macro
Date: 
Message-ID: <joswig-F929B6.17455313092007@news-europe.giganews.com>
In article <·······················@g4g2000hsf.googlegroups.com>,
 Eli Bendersky <······@gmail.com> wrote:

> On Sep 13, 12:34 pm, Rainer Joswig <······@lisp.de> wrote:
> > In article <························@19g2000hsx.googlegroups.com>,
> >  Eli Bendersky <······@gmail.com> wrote:
> >
> >
> >
> > > > Lisp excels at _____ (fill in the blank).  Now you've at least
> > > > eliminated some possibilities in your search.
> >
> > > > (Maybe you already filled-in the blank with this macro capability you
> > > > spoke of.  However, if it is difficult to find something here dramatic
> > > > enough to impress your friends, perhaps you can list other Lisp
> > > > "standout" features?  Or perhaps Lisp doesn't have one thing ultra-
> > > > dramatic in one particular category, but a lot of less dramatic things
> > > > in many categories, and these things all add up in the end?  If
> > > > nothing else, at least Lisp's syntax isn't nearly as grotesque and
> > > > burdensome as something like Java's.  Come on - look at a Java "Hello
> > > > World" program, with the class declaration, the "public static void
> > > > main," the "System.blah.whatever.printblah" hideousness, etc. - but
> > > > then again if it hasn't already occurred to a Java programmer to hate
> > > > all of that stuff, you are probably barking up the wrong tree with
> > > > trying to convert that particular person.)
> >
> > > > Regards.
> >
> > > But you see, as I mentioned in my original post, Lisp really stands
> > > out only in its macros, because all the rest was already implemented
> > > in other languages.
> >
> > Unfortunately in hundreds of languages. In Lisp you can have
> > it in one language.
> >
> 
> This is a good point. But it's true because of macros. With macros and
> Lisp's uniform syntax, I can not only write a library that implements
> anything I might deem important, but also make it look
> indistinguishable from native Lisp - extend the language itself.

Macros is only the packaging. It makes the tools more
programmer-friendly.

No, it is because Common Lisp has extensibility at many points built in.
But it also tries to find the balance between extensibility and
efficiency. The idea that code can be compiled is built into the
language. If you read the language spec, you will see this in many
places. Common Lisp is also a 'language'. Where Ruby and all the others
mix language definition and implementation reference. What ever
has been implemented in the lead implementation is suddenly
part of the language. Not so with Common Lisp. The language
is defined with the freedom for implementors to try widely
different implementation strategies. For example Common Lisp
as a language says nothing about sutomatic memory management. Still
most implementations will provide one.

Where can you extend / modify Common Lisp?

* you can create your own dialects in packages, reusing from other
  packages what is useful.

* you can change the interning of data via READ MACROS.
  This allows you also to change/extend the surface syntax.

* you can change the handling of Errors via the Condition System

* you can change the implementation of classes via meta classes

* you can change the printed representation via writing methods
  for print objects

* you can change the interpretation of expressions via macros

* you can write your own optimizers via compiler-macros

* you can compile any code at runtime

* you can interpret any code at runtime

* you can implement your own debugging tools via hooks

* you can change the way inheritance works

* you can change the way methods are combined

* you can shadow values via dynamic binding

* you can express hints to the compiler, so that
  the same code might run with totally different settings.

* you can execute arbitrary code at read time (if you allow that),
  compile time and load time. That has vast consequences. Instead of
  developing some template language, you can directly execute
  your Lisp code in the compile time environment.

Remember, this just the language definition. Above
will be portable over implementations.

If you look at individual implementations, you will see
even more possibilities. Even more for those who are
completely written in Lisp (including the compiler).

> > Sure with XML now everybody can describe data (and even procedures)
> > with a prefix language. Unfortunately the mechanisms are
> > ugly, monstrous and much less integrated.
> >
> > In Lisp I write
> >
> > (service-call "SVCL"
> >   (04 18 customer-name)
> >   (19 23 customer-id)
> >   (24 27 call-type-code)
> >   (28 35 date-of-call-string))
> >
> > and READ reads it. Plain and simple. No monstrous XML
> > parser. If I want to do something with it I apply
> > a function. If I want to compile it with the compiler
> > to some efficient procedure, I write a macro and
> > add it to the expression:
> >
> > (DEFMAPPING service-call "SVCL"
> >   (04 18 customer-name)
> >   (19 23 customer-id)
> >   (24 27 call-type-code)
> >   (28 35 date-of-call-string))
> >
> > Still I'm able to READ it, pretty print it, transform it.
> > All with mildly simple mechanisms.
> 
> Yes, but this already exists in other languages. Javascript has JSON
> which is almost like the Lisp way of storing data in s-expressions.

Javascript is in many ways like Lisp. It even has EVAL.

> YAML is also popular (and 99% equivalent to JSON).

Another language. Another tool.

We have JavaScript, Ruby, Rebol, Perl, Python, ... you name it.
All somewhat similar. All somewhat different. Each has some
special feature. Each lacks one. All are inefficient for
some types of application development. Common Lisp is
also inefficient for some types of application development,
but the range of possibilities is much larger.

> Yes, true - "at its core it is very extensible" *because* of macros.

No, macros are only the packaging. You might want to check
out 'The Art of the Metaobject-Protocol. It describes
CLOS and the Meta-object Protocol and even gives a simple
implementation. CLOS has a layered architecture. At the
core is CLOS itself (CLOS is written in CLOS), on top
of that is a functional layer and the Top-Level
macro layer makes it more convenient to use. But the macros
are not the implementation. They are the 'sugar'.

> Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
> has except macros. Ruby is the latest and greatest in the evolution
> path of modern programming languages and their convergence path with
> Lisp.
>
> Again, I'll use Norvig's "seven points that make Lisp
> different".
> 
> Ruby:
> 
> * It has a convenient built-in syntax for arrays and hash tables
> * Garbage collection
> * Dynamic typing - in fact the closest to Lisp yet (except maybe
> Smalltalk, with which I'm not familiar) with its duck typing
> philosophy
> * First class functions, with the syntactic sugar called "blocks"
> which makes a lot of higher-order functional paradigms very convenient
> * Interactive Environment - Ruby's "irb" is in many ways equivalent to
> the REPL. And Ruby slowly but surely gets the support of good IDEs -
> Emacs, Eclipse, Visual Studio, NetBeans and so on.
> * Extensibility - everything is modifiable, full reflection
> capabilities - you can even change built-in classes on the fly.
> module_eval and class_eval allow for much safer code generation than
> the string eval of Perl. Ruby is open enough to be the most convenient
> language, after Lisp of course, for writing DSLs.
> 
> * Uniform syntax: Bzzzzt! Nope. None, and so no *real* macros either.
> Ruby loses to Lisp on this point, and this is a big point,
> admittedly.
> 
> But when you tell people about this last point, they say - fine, but
> what's so great about these macros.
> And so we come back to the original reason for my starting this
> thread!
> 
> Eli
> 
> 
> 
> 
> [1] I see no reason why Ruby should be inherently less efficient than
> any other interpreted language. With its new VM in development, it has
> hope yet. And anyway, performance alone can't play that big a role.
> Ruby's interoperability with C is much simpler to work out than CL's
> CFFI, and writing critical code in C is very possible.

Sure, but most Lisp people I know prefer to write Lisp and not C.

There is no such thing like an 'interpreted language' Every
language can be interpreted. There are interpreters for C
and similar languages.

Implementations can be based on an Interpreter. When people say Ruby,
say mean mostly the lead implementation and the language it implements.
With Common Lisp the Spec is the lead and the implementations
try to compete to implement it 'best' and give the users useful
extensions. Common Lisp implementations have all kinds of
implementation strategies. Some will provide you with special
batch compilers which will use some of the assumptions they
are allowed to make.

With Ruby, since it is implemented in C, interoperability with C is
good (so is it with GCL, CLISP, ECLS and other Common Lisp which
are either implemented in C or compile to C). But Common Lisp
does not say to you if you want to write something somehow
efficient you need to use C. I'd say Common Lisp is much more
self-respecting as Ruby - the consequence is that many
Common Lisp implementations are written in Common Lisp. And not in C.

-- 
http://lispm.dyndns.org
From: Chris Russell
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189788327.380465.56210@r34g2000hsd.googlegroups.com>
On 13 Sep, 15:30, Eli Bendersky <······@gmail.com> wrote:

> Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
> has except macros. Ruby is the latest and greatest in the evolution
> path of modern programming languages and their convergence path with
> Lisp. Again, I'll use Norvig's "seven points that make Lisp
> different".
>
If you want something cool that lisp has that many languages don't,
consider the compile time type checking of dynamic type programs.
it's really nice to have a implementation that will catch:

(defun test()
 (let ((x 1))
   (setf x 'a)
   (+ 1 a)))

as a type error at compile time, and its something I really miss when
I'm debugging other peoples code in languages like R or matlab.
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5kvoq9F5jpc5U1@mid.individual.net>
Eli Bendersky wrote:

> Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
> has except macros. Ruby is the latest and greatest in the evolution
> path of modern programming languages and their convergence path with
> Lisp. 

So you're basically saying that Ruby is a very tall midget. ;)


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: Cesar Rabak
Subject: Re: A "killer" macro
Date: 
Message-ID: <fcfa23$1lo$1@aioe.org>
Pascal Costanza escreveu:
> Eli Bendersky wrote:
> 
>> Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
>> has except macros. Ruby is the latest and greatest in the evolution
>> path of modern programming languages and their convergence path with
>> Lisp. 
> 
> So you're basically saying that Ruby is a very tall midget. ;)
> 
> 
Probably yes, plus that the midget has enough height to catch all girls 
at the party as well... :-|
From: Pascal Costanza
Subject: Re: A "killer" macro
Date: 
Message-ID: <5l2cq6F60podU1@mid.individual.net>
Cesar Rabak wrote:
> Pascal Costanza escreveu:
>> Eli Bendersky wrote:
>>
>>> Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
>>> has except macros. Ruby is the latest and greatest in the evolution
>>> path of modern programming languages and their convergence path with
>>> Lisp. 
>>
>> So you're basically saying that Ruby is a very tall midget. ;)
>>
> Probably yes, plus that the midget has enough height to catch all girls 
> at the party as well... :-|

The tall midget may get more girls, but we get the smarter ones (who 
don't necessarily go to the parties). ;)


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: Marco Antoniotti
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189792649.698922.277350@y42g2000hsy.googlegroups.com>
On Sep 13, 10:30 am, Eli Bendersky <······@gmail.com> wrote:
> On Sep 13, 12:34 pm, Rainer Joswig <······@lisp.de> wrote:
>
>
>
> > In article <························@19g2000hsx.googlegroups.com>,
> >  Eli Bendersky <······@gmail.com> wrote:
>
> > > > Lisp excels at _____ (fill in the blank).  Now you've at least
> > > > eliminated some possibilities in your search.
>
> > > > (Maybe you already filled-in the blank with this macro capability you
> > > > spoke of.  However, if it is difficult to find something here dramatic
> > > > enough to impress your friends, perhaps you can list other Lisp
> > > > "standout" features?  Or perhaps Lisp doesn't have one thing ultra-
> > > > dramatic in one particular category, but a lot of less dramatic things
> > > > in many categories, and these things all add up in the end?  If
> > > > nothing else, at least Lisp's syntax isn't nearly as grotesque and
> > > > burdensome as something like Java's.  Come on - look at a Java "Hello
> > > > World" program, with the class declaration, the "public static void
> > > > main," the "System.blah.whatever.printblah" hideousness, etc. - but
> > > > then again if it hasn't already occurred to a Java programmer to hate
> > > > all of that stuff, you are probably barking up the wrong tree with
> > > > trying to convert that particular person.)
>
> > > > Regards.
>
> > > But you see, as I mentioned in my original post, Lisp really stands
> > > out only in its macros, because all the rest was already implemented
> > > in other languages.
>
> > Unfortunately in hundreds of languages. In Lisp you can have
> > it in one language.
>
> This is a good point. But it's true because of macros. With macros and
> Lisp's uniform syntax, I can not only write a library that implements
> anything I might deem important, but also make it look
> indistinguishable from native Lisp - extend the language itself.
>
>
>
> > Sure with XML now everybody can describe data (and even procedures)
> > with a prefix language. Unfortunately the mechanisms are
> > ugly, monstrous and much less integrated.
>
> > In Lisp I write
>
> > (service-call "SVCL"
> >   (04 18 customer-name)
> >   (19 23 customer-id)
> >   (24 27 call-type-code)
> >   (28 35 date-of-call-string))
>
> > and READ reads it. Plain and simple. No monstrous XML
> > parser. If I want to do something with it I apply
> > a function. If I want to compile it with the compiler
> > to some efficient procedure, I write a macro and
> > add it to the expression:
>
> > (DEFMAPPING service-call "SVCL"
> >   (04 18 customer-name)
> >   (19 23 customer-id)
> >   (24 27 call-type-code)
> >   (28 35 date-of-call-string))
>
> > Still I'm able to READ it, pretty print it, transform it.
> > All with mildly simple mechanisms.
>
> Yes, but this already exists in other languages. Javascript has JSON
> which is almost like the Lisp way of storing data in s-expressions.
> YAML is also popular (and 99% equivalent to JSON).
>
>
>
>
>
> > > Yes, 20 years ago Lisp was amazing - compared with
> > > C, Fortran and Pascal, but these days with Perl, Ruby and even C# 3.0
> > > around, the only thing that *really* sets Lisp apart is macros.
>
> > > Eli
>
> > That's plain wrong.
>
> > Macros are available in other programming languages, too.
>
> > Common Lisp is a multi-paradigm language that enables
> > interactive software development of small to very
> > large programs with somehow useful efficiency.
> > At its core it is very extensible to be able to
> > add very different programming paradigms.
>
> Yes, true - "at its core it is very extensible" *because* of macros.
>
> > PERL, Ruby and C# are very different. In Common Lisp
> > you can do most that those can in one package.
> > Ruby is totally inefficient (besides what is implemented
> > in C in its core) and there is little hope that it
> > can be better. You can write most Ruby stuff relatively
> > easy in Lisp, but if you try to use Ruby for Lisp
> > software be prepared for a hard time.
>
> Leaving inefficiency apart for the moment[1], Ruby has anything Lisp
> has except macros. Ruby is the latest and greatest in the evolution
> path of modern programming languages and their convergence path with
> Lisp. Again, I'll use Norvig's "seven points that make Lisp
> different".
>
> Ruby:
>
> * It has a convenient built-in syntax for arrays and hash tables
> * Garbage collection
> * Dynamic typing - in fact the closest to Lisp yet (except maybe
> Smalltalk, with which I'm not familiar) with its duck typing
> philosophy
> * First class functions, with the syntactic sugar called "blocks"
> which makes a lot of higher-order functional paradigms very convenient
> * Interactive Environment - Ruby's "irb" is in many ways equivalent to
> the REPL. And Ruby slowly but surely gets the support of good IDEs -
> Emacs, Eclipse, Visual Studio, NetBeans and so on.
> * Extensibility - everything is modifiable, full reflection
> capabilities - you can even change built-in classes on the fly.
> module_eval and class_eval allow for much safer code generation than
> the string eval of Perl. Ruby is open enough to be the most convenient
> language, after Lisp of course, for writing DSLs.
>
> * Uniform syntax: Bzzzzt! Nope. None, and so no *real* macros either.
> Ruby loses to Lisp on this point, and this is a big point,
> admittedly.
>
> But when you tell people about this last point, they say - fine, but
> what's so great about these macros.
> And so we come back to the original reason for my starting this
> thread!
>
> Eli
>
> [1] I see no reason why Ruby should be inherently less efficient than
> any other interpreted language.

I would not know.  But it is surely less efficiente than a compiled
language like Common Lisp.

> With its new VM in development, it has
> hope yet. And anyway, performance alone can't play that big a role.
> Ruby's interoperability with C is much simpler to work out than CL's
> CFFI, and writing critical code in C is very possible.

CFFI is used to interface to existing libraries written in C.  With
CL, thanks to the built in function COMPILE, you almost never need to
resort to C.

Cheers

Marco
From: Slobodan Blazeski
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189716384.544639.234040@o80g2000hse.googlegroups.com>
On Sep 13, 11:30 am, Eli Bendersky <······@gmail.com> wrote:
> > Lisp excels at _____ (fill in the blank).  Now you've at least
> > eliminated some possibilities in your search.
>
> > (Maybe you already filled-in the blank with this macro capability you
> > spoke of.  However, if it is difficult to find something here dramatic
> > enough to impress your friends, perhaps you can list other Lisp
> > "standout" features?  Or perhaps Lisp doesn't have one thing ultra-
> > dramatic in one particular category, but a lot of less dramatic things
> > in many categories, and these things all add up in the end?  If
> > nothing else, at least Lisp's syntax isn't nearly as grotesque and
> > burdensome as something like Java's.  Come on - look at a Java "Hello
> > World" program, with the class declaration, the "public static void
> > main," the "System.blah.whatever.printblah" hideousness, etc. - but
> > then again if it hasn't already occurred to a Java programmer to hate
> > all of that stuff, you are probably barking up the wrong tree with
> > trying to convert that particular person.)
>
> > Regards.
>
> But you see, as I mentioned in my original post, Lisp really stands
> out only in its macros, because all the rest was already implemented
> in other languages. Yes, 20 years ago Lisp was amazing - compared with
> C, Fortran and Pascal, but these days with Perl, Ruby and even C# 3.0
> around, the only thing that *really* sets Lisp apart is macros.
>
> Eli- Hide quoted text -
>
Elis I found your post newbish. You want somebody else to show you a
great macro just to convince your friends that lisp is a great
language. And after doing a side by side, feature by feature
comparasion with Perl, Ruby and C# 3.0 you concluded that lisp has
nothing new to offer beside macros.

Actually the true  is that  people already show you  great macros but
you're just unable to see them as such. It reminds me of a tv show
about Gregor Mendel, the father of genetics. It goes something like
this: Mendel shows his conclusions about experiments he done with peas
to some eminent professor and his assistent. The professor finally
says to his assistent  awesome ,bravo, look what Mendel done with
peas, congratulate him. And the assistent says: But I don't eat peas.

What I like about lisp is very fast development , you get idea you try
it, fix it , there is no compiler to punch you in your nose everytime
you mispell or don't define some function , or call it with wrong
arguments, nor there are stupid scripts to load, change, reload WTF.
It's only you and the repl, you write and rewrite and stop only to do
thinking. The lisp implementation is your best friend not that boring
perfectionistic teacher  that always fallows stupid rules and you're
forced to lie, cheat and use tricks only to have some fun.  Lisp code
doesn't start with brilliant macros carved in stone, it's starts with
a lot of messy defuns, some classes, a lot of rewrites while you're
gaining knowledge of the probem you're trying to solve, than you're
starting to clean up the rats nest, remove unneeded globals, search
for patterns that first combine themselves in functions, and finally
when functions can't do the trick, the mighty macros took over,
Kaizen   -continous change for the better, and finally there's  stood
the remaining code. And it's a beatifull code, something that makes
you feel proud, and sparks the touch of creation, you feel
selffullfillment.
Eli
There's nothing special in lisp programs, the journey to write them is
magical.

After the problem is solved, you could rewrite it in different
languages, with different levels of succcess. Some of them will yield
code that's even shorter, or faster , or maybe even prettier. Question
is could you write that same code directly in you-name it language?
Well I coudn't.

Slobodan
From: John Thingstad
Subject: Re: A "killer" macro
Date: 
Message-ID: <op.tyl3pkzxpqzri1@pandora.upc.no>
P� Thu, 13 Sep 2007 22:46:24 +0200, skrev Slobodan Blazeski  
<·················@gmail.com>:

>
> After the problem is solved, you could rewrite it in different
> languages, with different levels of succcess. Some of them will yield
> code that's even shorter, or faster , or maybe even prettier. Question
> is could you write that same code directly in you-name it language?
> Well I coudn't.

Well if you are a beginner you will probably spend most of your time  
buried in the CLHS looking for a function or feature. It is less of a  
problem now than when I started but still to some extent true. You need to  
be somewhat fluent before any of this great productivity shows up. That is  
why it is to difficult to convince new peole. Lisp is a language that  
grows on you gradually. It doesn't immediately strike you neither as  
beautiful or productive.  At least that was true for me. My first Lisp  
programs were clumsy. A form of C in Lisp. It has taken me years to  
'think' Lisp (I still hit the wall some times). For this reason I am not  
convinced a 'killer macro' is going to do it. Particularly it is highly  
unlikely they will understand it. It will just look cryptic and confusing.

The best intro I have seen is the first chapter of Practical Common Lisp.  
This is because you get into the mind of someone who knows the language  
and see the interactive style. You see the program start with a few key  
ideas and evolve into a mature form. Perhaps this is a better way to  
introduce it?

I was going to stay out of this discussion, but I guess I couldn't help  
myself.
Well.. Just my to cents.
From: Jason  Sidabras
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189732263.321273.273450@19g2000hsx.googlegroups.com>
>
> Elis I found your post newbish. You want somebody else to show you a
> great macro just to convince your friends that lisp is a great
> language. And after doing a side by side, feature by feature
> comparasion with Perl, Ruby and C# 3.0 you concluded that lisp has
> nothing new to offer beside macros.
>
> Actually the true  is that  people already show you  great macros but
> you're just unable to see them as such. It reminds me of a tv show
> about Gregor Mendel, the father of genetics. It goes something like
> this: Mendel shows his conclusions about experiments he done with peas
> to some eminent professor and his assistent. The professor finally
> says to his assistent  awesome ,bravo, look what Mendel done with
> peas, congratulate him. And the assistent says: But I don't eat peas.
>
> What I like about lisp is very fast development , you get idea you try
> it, fix it , there is no compiler to punch you in your nose everytime
> you mispell or don't define some function , or call it with wrong
> arguments, nor there are stupid scripts to load, change, reload WTF.
> It's only you and the repl, you write and rewrite and stop only to do
> thinking. The lisp implementation is your best friend not that boring
> perfectionistic teacher  that always fallows stupid rules and you're
> forced to lie, cheat and use tricks only to have some fun.  Lisp code
> doesn't start with brilliant macros carved in stone, it's starts with
> a lot of messy defuns, some classes, a lot of rewrites while you're
> gaining knowledge of the probem you're trying to solve, than you're
> starting to clean up the rats nest, remove unneeded globals, search
> for patterns that first combine themselves in functions, and finally
> when functions can't do the trick, the mighty macros took over,
> Kaizen   -continous change for the better, and finally there's  stood
> the remaining code. And it's a beatifull code, something that makes
> you feel proud, and sparks the touch of creation, you feel
> selffullfillment.
> Eli
> There's nothing special in lisp programs, the journey to write them is
> magical.
>
> After the problem is solved, you could rewrite it in different
> languages, with different levels of succcess. Some of them will yield
> code that's even shorter, or faster , or maybe even prettier. Question
> is could you write that same code directly in you-name it language?
> Well I coudn't.
>
> Slobodan

This reply is beautiful and poetic. The passion behind LISP users is
amazing and one of the reasons that I am starting to learn LISP.
From: Ken Tilton
Subject: Re: A "killer" macro
Date: 
Message-ID: <dVoGi.143$Uk3.4@newsfe12.lga>
Jason Sidabras wrote:
>>Elis I found your post newbish. You want somebody else to show you a
>>great macro just to convince your friends that lisp is a great
>>language. And after doing a side by side, feature by feature
>>comparasion with Perl, Ruby and C# 3.0 you concluded that lisp has
>>nothing new to offer beside macros.
>>
>>Actually the true  is that  people already show you  great macros but
>>you're just unable to see them as such. It reminds me of a tv show
>>about Gregor Mendel, the father of genetics. It goes something like
>>this: Mendel shows his conclusions about experiments he done with peas
>>to some eminent professor and his assistent. The professor finally
>>says to his assistent  awesome ,bravo, look what Mendel done with
>>peas, congratulate him. And the assistent says: But I don't eat peas.
>>
>>What I like about lisp is very fast development , you get idea you try
>>it, fix it , there is no compiler to punch you in your nose everytime
>>you mispell or don't define some function , or call it with wrong
>>arguments,

<cough> What lisp is Slobby using? Anyway...

> nor there are stupid scripts to load, change, reload WTF.
>>It's only you and the repl, you write and rewrite and stop only to do
>>thinking. The lisp implementation is your best friend not that boring
>>perfectionistic teacher  that always fallows stupid rules and you're
>>forced to lie, cheat and use tricks only to have some fun.  Lisp code
>>doesn't start with brilliant macros carved in stone, it's starts with
>>a lot of messy defuns, some classes, a lot of rewrites while you're
>>gaining knowledge of the probem you're trying to solve, than you're
>>starting to clean up the rats nest, remove unneeded globals, search
>>for patterns that first combine themselves in functions, and finally
>>when functions can't do the trick, the mighty macros took over,
>>Kaizen   -continous change for the better, and finally there's  stood
>>the remaining code. And it's a beatifull code, something that makes
>>you feel proud, and sparks the touch of creation, you feel
>>selffullfillment.
>>Eli
>>There's nothing special in lisp programs, the journey to write them is
>>magical.
>>
>>After the problem is solved, you could rewrite it in different
>>languages, with different levels of succcess. Some of them will yield
>>code that's even shorter, or faster , or maybe even prettier. Question
>>is could you write that same code directly in you-name it language?
>>Well I coudn't.
>>
>>Slobodan
> 
> 
> This reply is beautiful and poetic. The passion behind LISP users is
> amazing and one of the reasons that I am starting to learn LISP.
> 

Yes, at long last there is someone to whom I can pass The Torch. A 
Farewell Tour of local Lisp groups is in the works. Slobby you'll find 
the key to the kennel under your mat.

The Kenny is dead! Long live The Slobby!
From: Marco Antoniotti
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189792377.311062.290860@50g2000hsm.googlegroups.com>
On Sep 13, 5:30 am, Eli Bendersky <······@gmail.com> wrote:
> > Lisp excels at _____ (fill in the blank).  Now you've at least
> > eliminated some possibilities in your search.
>
> > (Maybe you already filled-in the blank with this macro capability you
> > spoke of.  However, if it is difficult to find something here dramatic
> > enough to impress your friends, perhaps you can list other Lisp
> > "standout" features?  Or perhaps Lisp doesn't have one thing ultra-
> > dramatic in one particular category, but a lot of less dramatic things
> > in many categories, and these things all add up in the end?  If
> > nothing else, at least Lisp's syntax isn't nearly as grotesque and
> > burdensome as something like Java's.  Come on - look at a Java "Hello
> > World" program, with the class declaration, the "public static void
> > main," the "System.blah.whatever.printblah" hideousness, etc. - but
> > then again if it hasn't already occurred to a Java programmer to hate
> > all of that stuff, you are probably barking up the wrong tree with
> > trying to convert that particular person.)
>
> > Regards.
>
> But you see, as I mentioned in my original post, Lisp really stands
> out only in its macros, because all the rest was already implemented
> in other languages. Yes, 20 years ago Lisp was amazing - compared with
> C, Fortran and Pascal, but these days with Perl, Ruby and even C# 3.0
> around, the only thing that *really* sets Lisp apart is macros.
>
> Eli

... and multimethods and the "what you print is what you read is what
you print" principle and I have not seen any convincing equivalent of
DISASSEMBLE in either Perl, Ruby etc etc.

Cheers

Marco
From: Damien Kick
Subject: Re: A "killer" macro
Date: 
Message-ID: <13fk0icrq651l24@corp.supernews.com>
··············@yahoo.com wrote:
> I was asked a while back to code up a poker simulation for a project.
> I did this in Smalltalk, [...]
> 
> However, upon reevaluating the solution and reflecting on it, I saw
> where another language could have done "the core" of the program (hand
> evaluation) much better, and in much less length of code, with far
> less possibility (none) of bugs.  This language was Prolog.  [...]
> 
> To illustrate the conciseness of the Prolog solution, here is the code
> to recognize a "4 of a kind":
> 
> quad(A,B,C,D,E,F,G) :- permutation([A,B,C,D,E,F,G],[X,X,X,X,_,_,_]).
> 
> That's it - one line of code, and the input doesn't even need to be
> sorted beforehand, as the old solution's input did, so I get to remove
> an unnecessary sort.

The first time I think I was really blown away with the power of the 
programmable programming language was Peter Norvig's implementation of 
Prolog in Lisp.

(<- (quad ?a ?b ?c ?d ?e ?f ?g)
     (permutation (?a ?b ?c ?d ?e ?f ?g)
                  (?x ?x ?x ?x ?  ?  ?)))

However, I realize that his implementation definitely does not meet the 
criterion of being easy to present.  On the other hand, a few simple 
examples of what can be done with it at the end of the day is, IMO, 
killer.  I really don't know how one would do something like this as 
elegantly as he does it in another language.  Especially when one can 
begin mixing and matching Prolog and Lisp, weaving the two together. 
Perhaps a bit of a contrived example, but:

(defmacro define-of-a-kind (number name)
   (with-gensyms (?a ?b ?c ?d ?e ?f ?g ?x)
     ` (<- (,name ,?a ,?b ,?c ,?d ,?e ,?f ,?g)
           (permutation (,?a ,?b ,?c ,?d ,?e ,?f ,?g)
                        (,@(loop repeat number collect ?x)
                         ,@(loop repeat (- 7 number) collect '?))))))

(define-of-a-kind 4 quad)

And his implementation uses macros, CPS, invoking the compiler at 
runtime, and implements a Prolog with Lisp as a FFI.  How cool is that?
From: Josip Gracin
Subject: Re: A "killer" macro
Date: 
Message-ID: <fddu5t$i3c$1@sunce.iskon.hr>
Hi!  A bit late, but nevertheless...

Here's an example of code I find very inspiring.  I sometimes use it 
when I preach.

 From SBCL source, file src/assembly/x86/assem-rtns.lisp:
========================================================

(define-assembly-routine
     (tail-call-variable
      (:return-style :none))

     ((:temp eax unsigned-reg eax-offset)
      (:temp ebx unsigned-reg ebx-offset)
      (:temp ecx unsigned-reg ecx-offset)
      (:temp edx unsigned-reg edx-offset)
      (:temp edi unsigned-reg edi-offset)
      (:temp esi unsigned-reg esi-offset))

   ;; Calculate NARGS (as a fixnum)
   (move ecx esi)
   (inst sub ecx esp-tn)

   ;; Check for all the args fitting the registers.
   (inst cmp ecx (fixnumize 3))
   (inst jmp :le REGISTER-ARGS)

   ;; Save the OLD-FP and RETURN-PC because the blit it going to trash
   ;; those stack locations. Save the ECX, because the loop is going
   ;; to trash it.
   (pushw ebp-tn -1)
   (loadw ebx ebp-tn -2)
   (inst push ecx)

[.... cut for this post ....]

   ;; Clear most of the stack.
   (inst lea esp-tn
         (make-ea :dword :base ebp-tn :disp (* -3 n-word-bytes)))

   ;; Push the return-pc so it looks like we just called.
   (pushw ebp-tn -2)

   ;; And away we go.
   (inst jmp (make-ea-for-object-slot eax closure-fun-slot 
fun-pointer-lowtag)))
From: Dimiter "malkia" Stanev
Subject: Re: A "killer" macro
Date: 
Message-ID: <5ktbigF52b2dU1@mid.individual.net>
Yup! I've actually tried them, but for this particular case, I needed 
performance as much as possible, and unfortunately I was unable to get 
replace or subseq working fast enough for me. Actually I don't think 
I've tried subseq well enough, but replace on most LISP compilers was a 
function call, not really optimal to call it when comes to couple of 
average transfer.

I would definitely check subseq again :)

Madhu wrote:
> Helu
> 
> * "Dimiter <······@gmail.com> <··············@mid.individual.net> :
> 
> | For a code that was doing LZO decompression, I've added the following
> | macros, that were "simulating" how for example "*p++ = value", or
> | "*p++ = *x++", or memcpy(). Granted not the best macros, but minimized
> | my code.
> |
> <SNIP>
> | Here is an example of how to use them
> |
> | The following would copy 15 bytes from the source-array starting from
> | the source-index, in the dest-array, starting from the dest-index. It
> | would then increase dest-index and source-index by 15.
> |
> |    (acpy++ dest-array dest-index source-array source-index 15)
> 
> Just FYI that should equivalent to
> 
> (replace dest-array source-array :start1 dest-index :start2
> 	:source-index :end2 (+ source-index 15))
> 
> or using a macro:
> (setf (subseq dest-array dest-index)
>       (subseq source-array source-index (+ source-index 15)))
> 
> [untested]
> 
> | Also note that this would check whether the number of indexes is
> | constant, and in the case above it is (15), so it would actually
> | unroll that, instead of loop it.
> --
> Madhu
From: Alan Crowe
Subject: Re: A "killer" macro
Date: 
Message-ID: <86sl5jsra4.fsf@cawtech.freeserve.co.uk>
Eli Bendersky <······@gmail.com> writes:

> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.
> 
> Any suggestions for such an example ?
> 

Many computer programming languages have the concept of an
enumeration or symbolic constant. At compile time the
constant is a string of characters, meaningful to humans,
but comparision is character by character, so long names are
slower than short names. At run time this name has gone
away, leaving a number fitting in a machine word. So items
from small sets are represented efficiently, as a code
number in a machine word, while the programmer does not have
to learn the code numbers. He programs with symbolic names.

Lisp has a better idea - the translation from names to
numbers takes place at read time, and the number is the
address of the symbol. We get the efficiency of representing
the constant as a single word, but the name is still
available at run-time.

However, sometimes the coding scheme for these code numbers
is not internal to the program. Sometimes the numbers come
from outside, as for example in the instruction set of a
microprocessor. The first idea here is something like

(defconstant load 8)
(defconstant store 9)

but CL:CASE stops working.

(case mnemonic
  (load ....)
  (store ...)

has to be replace by

(case mnemonic
  (8 ...)
  (9 ...)

which is unacceptable.

A better idea is to stick with symbols and write assemby and
disassembly functions, so that

(motorola6800 'load) => 10
(intel8086 'load) => 32

(motorola6800 10) => load
(intel8086 10) => decrement

or whatever, I don't know the actual code.

Well, that is a potentially better idea. You don't what to
be stuck for hours typing these things. You want want to be
type in something simple, such as

(define-opcodes mc6809
 (8 load store
  16 add sub mul div
  24 fetch write))

On the other hand, they might get heavily used, the program
had better scale well. The target is for constant time
translation, regardless of the number of opcodes.

So one design is to have a vector of symbols, with each
symbol in the right place to be looked up directly, and to
use the machine name as an indicator on each symbols plist,
giving the opcode behind that mnemonic on that architecture.

At this point I just paste in the file from alan/lisp/utils

#| the built in case macro doesn't evaluate the keys

This causes grief when you want symbols to work like C-style
#define LOAD 0
#define STORE 3
#define ADD 4
#define SUBTRACT 5

(defmacro define-opcodes ... )

(define-opcodes octium (0 load 3 store add subtract))

and then you have 

(octium 'store) => 3
(octium 4) => add

You work with symbols and case works fine.
The bonus is that you can define different encodings and
parameterise your assembler and dis-assembler

(funcall #'machine opcode) => mnemonic

|#

(defmacro define-opcodes (machine condensed-list)
  "number mnemonic mnemnonic number ...."
           (let* ((code-assoc (expand condensed-list))
                  (least-opcode (reduce #'min code-assoc :key #'cdr)))
             `(let ((opcode-vector ,(make-decode-table code-assoc least-opcode))
                    (least-opcode ,least-opcode))
               (defun ,machine (thing)
                 (etypecase thing
                   (number (aref opcode-vector (- thing least-opcode)))
                   (symbol (get thing ',machine))))
               ,(cons 'setf
                      (loop for (mnemonic . code) in code-assoc
                            append
                            `((get ',mnemonic ',machine) ,code)))
               ',machine)))

(defun expand (list)
           (let ((expansion '())
                 (index 0))
             (dolist (item list expansion)
               (etypecase item
                 (symbol (push (cons item index) expansion)
                         (incf index))
                 ((integer 0) (setf index item))))))

(defun make-decode-table (code-assoc least-opcode)
  (let ((greatest-opcode (reduce #'max
                                 code-assoc
                                 :key #'cdr)))
    (let ((table (make-array (+ 1 (- greatest-opcode
                                     least-opcode)))))
      (loop for (mnemonic . code) in code-assoc
            do (setf (aref table (- code least-opcode))
                     mnemonic))
      table)))

Quite a short file.

(macroexpand-1 '(define-opcodes mc6809
 (8 load store
  16 add sub mul div
  24 fetch write)))
=>
(LET ((OPCODE-VECTOR
       #(LOAD STORE 0 0 0 0 0 0 ADD SUB MUL DIV 0 0 0 0 FETCH WRITE))
      (LEAST-OPCODE 8))
  (DEFUN MC6809 (THING)
    (ETYPECASE THING
      (NUMBER (AREF OPCODE-VECTOR (- THING LEAST-OPCODE)))
      (SYMBOL (GET THING 'MC6809))))
  (SETF (GET 'WRITE 'MC6809)
          25
        (GET 'FETCH 'MC6809)
          24
        (GET 'DIV 'MC6809)
          19
        (GET 'MUL 'MC6809)
          18
        (GET 'SUB 'MC6809)
          17
        (GET 'ADD 'MC6809)
          16
        (GET 'STORE 'MC6809)
          9
        (GET 'LOAD 'MC6809)
          8)
  'MC6809)
T

I've not used this for real. If I were going to I would add
more error checking (and some eval-when), which would make
it more complicated and less useful as a simple example.

I think it serves to bring out the idea of writing code, and
not just pasting code into a template, while being
unsophisticated enough to explain to non-lispers.

Alan Crowe
Edinburgh
Scotland
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189674701.771666.275640@50g2000hsm.googlegroups.com>
On Sep 12, 7:54 pm, Alan Crowe <····@cawtech.freeserve.co.uk> wrote:
> Eli Bendersky <······@gmail.com> writes:
> > In short: I'm looking for a "killer" macro - a macro (or a couple of
> > related ones) that show what Lisp can do and other languages (those
> > without uniform syntax) can not.
>
> > Any suggestions for such an example ?
>
> Many computer programming languages have the concept of an
> enumeration or symbolic constant. At compile time the
> constant is a string of characters, meaningful to humans,
> but comparision is character by character, so long names are
> slower than short names. At run time this name has gone
> away, leaving a number fitting in a machine word. So items
> from small sets are represented efficiently, as a code
> number in a machine word, while the programmer does not have
> to learn the code numbers. He programs with symbolic names.
>
> Lisp has a better idea - the translation from names to
> numbers takes place at read time, and the number is the
> address of the symbol. We get the efficiency of representing
> the constant as a single word, but the name is still
> available at run-time.
>
> However, sometimes the coding scheme for these code numbers
> is not internal to the program. Sometimes the numbers come
> from outside, as for example in the instruction set of a
> microprocessor. The first idea here is something like
>
> (defconstant load 8)
> (defconstant store 9)
>
> but CL:CASE stops working.
>
> (case mnemonic
>   (load ....)
>   (store ...)
>
> has to be replace by
>
> (case mnemonic
>   (8 ...)
>   (9 ...)
>
> which is unacceptable.
>
> A better idea is to stick with symbols and write assemby and
> disassembly functions, so that
>
> (motorola6800 'load) => 10
> (intel8086 'load) => 32
>
> (motorola6800 10) => load
> (intel8086 10) => decrement
>
> or whatever, I don't know the actual code.
>
> Well, that is a potentially better idea. You don't what to
> be stuck for hours typing these things. You want want to be
> type in something simple, such as
>
> (define-opcodes mc6809
>  (8 load store
>   16 add sub mul div
>   24 fetch write))
>
> On the other hand, they might get heavily used, the program
> had better scale well. The target is for constant time
> translation, regardless of the number of opcodes.
>
> So one design is to have a vector of symbols, with each
> symbol in the right place to be looked up directly, and to
> use the machine name as an indicator on each symbols plist,
> giving the opcode behind that mnemonic on that architecture.
>
> At this point I just paste in the file from alan/lisp/utils
>
> #| the built in case macro doesn't evaluate the keys
>
> This causes grief when you want symbols to work like C-style
> #define LOAD 0
> #define STORE 3
> #define ADD 4
> #define SUBTRACT 5
>
> (defmacro define-opcodes ... )
>
> (define-opcodes octium (0 load 3 store add subtract))
>
> and then you have
>
> (octium 'store) => 3
> (octium 4) => add
>
> You work with symbols and case works fine.
> The bonus is that you can define different encodings and
> parameterise your assembler and dis-assembler
>
> (funcall #'machine opcode) => mnemonic
>
> |#
>
> (defmacro define-opcodes (machine condensed-list)
>   "number mnemonic mnemnonic number ...."
>            (let* ((code-assoc (expand condensed-list))
>                   (least-opcode (reduce #'min code-assoc :key #'cdr)))
>              `(let ((opcode-vector ,(make-decode-table code-assoc least-opcode))
>                     (least-opcode ,least-opcode))
>                (defun ,machine (thing)
>                  (etypecase thing
>                    (number (aref opcode-vector (- thing least-opcode)))
>                    (symbol (get thing ',machine))))
>                ,(cons 'setf
>                       (loop for (mnemonic . code) in code-assoc
>                             append
>                             `((get ',mnemonic ',machine) ,code)))
>                ',machine)))
>
> (defun expand (list)
>            (let ((expansion '())
>                  (index 0))
>              (dolist (item list expansion)
>                (etypecase item
>                  (symbol (push (cons item index) expansion)
>                          (incf index))
>                  ((integer 0) (setf index item))))))
>
> (defun make-decode-table (code-assoc least-opcode)
>   (let ((greatest-opcode (reduce #'max
>                                  code-assoc
>                                  :key #'cdr)))
>     (let ((table (make-array (+ 1 (- greatest-opcode
>                                      least-opcode)))))
>       (loop for (mnemonic . code) in code-assoc
>             do (setf (aref table (- code least-opcode))
>                      mnemonic))
>       table)))
>
> Quite a short file.
>
> (macroexpand-1 '(define-opcodes mc6809
>  (8 load store
>   16 add sub mul div
>   24 fetch write)))
> =>
> (LET ((OPCODE-VECTOR
>        #(LOAD STORE 0 0 0 0 0 0 ADD SUB MUL DIV 0 0 0 0 FETCH WRITE))
>       (LEAST-OPCODE 8))
>   (DEFUN MC6809 (THING)
>     (ETYPECASE THING
>       (NUMBER (AREF OPCODE-VECTOR (- THING LEAST-OPCODE)))
>       (SYMBOL (GET THING 'MC6809))))
>   (SETF (GET 'WRITE 'MC6809)
>           25
>         (GET 'FETCH 'MC6809)
>           24
>         (GET 'DIV 'MC6809)
>           19
>         (GET 'MUL 'MC6809)
>           18
>         (GET 'SUB 'MC6809)
>           17
>         (GET 'ADD 'MC6809)
>           16
>         (GET 'STORE 'MC6809)
>           9
>         (GET 'LOAD 'MC6809)
>           8)
>   'MC6809)
> T
>
> I've not used this for real. If I were going to I would add
> more error checking (and some eval-when), which would make
> it more complicated and less useful as a simple example.
>
> I think it serves to bring out the idea of writing code, and
> not just pasting code into a template, while being
> unsophisticated enough to explain to non-lispers.
>
> Alan Crowe
> Edinburgh
> Scotland

Alan,

This is an interesting example, but except for the minor nicety of
opcode numbers growing automatically, it looks just like a
sophisticated way to work around the limitations of the "case" macro.
Why not just write an "evaluating case" macro and get done with it ?
Writing macros to overcome problems in other macros isn't a good
example of a language's power. Besides, someone can correctly note he
just does this easily in C:

#define LOAD 0
#define STORE 3
#define ADD STORE+1
#define SUBTRACT STORE+2
From: Emilio Lopes
Subject: Re: A "killer" macro
Date: 
Message-ID: <ycd4wnohre.fsf@freenet.de>
Eli Bendersky writes:

> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.

Here is my take: a simple macro called `debug', which prints a given
*expression* followed by its value.  As a convenience it also returns
this same value.

I'd be interested to know how you could achieve this in languages
missing macros and `quote'.

This answer uses Scheme, but porting to CL's `defmacro' should be
simple.

Supose you define `my-function' as follows:

   (define (my-function x y z)
     (* 2 (debug (+ x y z))))

If you call `(my-function 3 4 2)' it will now print

   ### (+ x y z): 9

and return 18.

Here is the macro definition:

   (define-syntax debug
     (syntax-rules ()
       ((_ expr)
        (let ((literal (quote expr))
              (value expr))
          (display "### ")
          (display literal)
          (display ": ")
          (write value)
          (newline)
          value))
       ((_ expr expr1 ...)
        (begin
          (debug expr)
          (debug expr1 ...)))))

See also

   http://programming.reddit.com/info/ujj3/comments/cuqof

where someone asked this same question.

-- 
Em�lio C. Lopes
Munich, Germany
From: Raymond Wiker
Subject: Re: A "killer" macro
Date: 
Message-ID: <m2hclzy8xr.fsf@RawMBP.local>
Emilio Lopes <·····@gmx.net> writes:

> Eli Bendersky writes:
>
>> In short: I'm looking for a "killer" macro - a macro (or a couple of
>> related ones) that show what Lisp can do and other languages (those
>> without uniform syntax) can not.
>
> Here is my take: a simple macro called `debug', which prints a given
> *expression* followed by its value.  As a convenience it also returns
> this same value.
>
> I'd be interested to know how you could achieve this in languages
> missing macros and `quote'.
>
> This answer uses Scheme, but porting to CL's `defmacro' should be
> simple.
>
> Supose you define `my-function' as follows:
>
>    (define (my-function x y z)
>      (* 2 (debug (+ x y z))))
>
> If you call `(my-function 3 4 2)' it will now print
>
>    ### (+ x y z): 9
>
> and return 18.
>
> Here is the macro definition:
>
>    (define-syntax debug
>      (syntax-rules ()
>        ((_ expr)
>         (let ((literal (quote expr))
>               (value expr))
>           (display "### ")
>           (display literal)
>           (display ": ")
>           (write value)
>           (newline)
>           value))
>        ((_ expr expr1 ...)
>         (begin
>           (debug expr)
>           (debug expr1 ...)))))
>
> See also
>
>    http://programming.reddit.com/info/ujj3/comments/cuqof

Not a convincing example of the power of (Lisp) macros; even C++ can do this:

#include <iostream>
#include <cmath>

#define DEBUG(a) (std::cerr << "### " << #a << ": " << (a) << std::endl, a)

main()
{
  DEBUG(1 + 1);
  DEBUG(asin(1.0));

  float a = DEBUG(1 + 1) + DEBUG(asin(1.0)) + 3.14;

  std::cerr << a << std::endl;
}
From: Rob Warnock
Subject: Re: A "killer" macro
Date: 
Message-ID: <74idnTlKL5jXB3XbnZ2dnUVZ_vyinZ2d@speakeasy.net>
Raymond Wiker  <···@RawMBP.local> wrote:
+---------------
| Emilio Lopes <·····@gmx.net> writes:
| > Here is my take: a simple macro called `debug', which
| > prints a given *expression* followed by its value.
...
| > Here is the macro definition [in Scheme]:
| >    (define-syntax debug
| >      (syntax-rules () ...))
| >        ((_ expr)
| >         (let ((literal (quote expr))
| >               (value expr))
| >           (display "### ")
| >           (display literal)
| >           (display ": ")
| >           (write value)
| >           (newline)
| >           value))
| >        ((_ expr expr1 ...)
| >         (begin
| >           (debug expr)
| >           (debug expr1 ...)))))
...
| Not a convincing example of the power of (Lisp) macros;
| even C++ can do this: ...
| #define DEBUG(a) (std::cerr << "### " << #a << ": " << (a) << std::endl, a)
+---------------

*BZZZTT!!* Your C++ macro only takes *one* expression;
his takes an *arbitrary* number of expressions in a
single call of the macro!! Let's see you do *that* in C++!!


-Rob

p.s. The one from my personal toolbox, in CL:

    > (defmacro dbgv ((&optional (where "Some Unknown Location..."))
		       &rest forms)
	`(progn
	   (format t "~&DBGV: @~a:~%" ',where)
	   ,@(loop for form in forms
	       collect `(format t "~s = ~s~%" ',form ,form))))

    DBGV
    > (dbgv (the-repl) (+ 1 2) (expt 2 100) (strcat "foo" "bar"))

    DBGV: @THE-REPL:
    (+ 1 2) = 3
    (EXPT 2 100) = 1267650600228229401496703205376
    (STRCAT "foo" "bar") = "foobar"
    NIL
    > 

I suspose I could make it return the last value like Emilio's does,
but I haven't found the need for that yet.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Eli Bendersky
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189675471.138486.237270@19g2000hsx.googlegroups.com>
On Sep 13, 4:02 am, ····@rpw3.org (Rob Warnock) wrote:
> Raymond Wiker  <····@RawMBP.local> wrote:
> +---------------
> | Emilio Lopes <·····@gmx.net> writes:
> | > Here is my take: a simple macro called `debug', which
> | > prints a given *expression* followed by its value.
> ...
> | > Here is the macro definition [in Scheme]:
> | >    (define-syntax debug
> | >      (syntax-rules () ...))
> | >        ((_ expr)
> | >         (let ((literal (quote expr))
> | >               (value expr))
> | >           (display "### ")
> | >           (display literal)
> | >           (display ": ")
> | >           (write value)
> | >           (newline)
> | >           value))
> | >        ((_ expr expr1 ...)
> | >         (begin
> | >           (debug expr)
> | >           (debug expr1 ...)))))
> ...
> | Not a convincing example of the power of (Lisp) macros;
> | even C++ can do this: ...
> | #define DEBUG(a) (std::cerr << "### " << #a << ": " << (a) << std::endl, a)
> +---------------
>
> *BZZZTT!!* Your C++ macro only takes *one* expression;
> his takes an *arbitrary* number of expressions in a
> single call of the macro!! Let's see you do *that* in C++!!
>
> -Rob
>
> p.s. The one from my personal toolbox, in CL:
>
>     > (defmacro dbgv ((&optional (where "Some Unknown Location..."))
>                        &rest forms)
>         `(progn
>            (format t "~&DBGV: @~a:~%" ',where)
>            ,@(loop for form in forms
>                collect `(format t "~s = ~s~%" ',form ,form))))
>
>     DBGV
>     > (dbgv (the-repl) (+ 1 2) (expt 2 100) (strcat "foo" "bar"))
>
>     DBGV: @THE-REPL:
>     (+ 1 2) = 3
>     (EXPT 2 100) = 1267650600228229401496703205376
>     (STRCAT "foo" "bar") = "foobar"
>     NIL
>     >
>
> I suspose I could make it return the last value like Emilio's does,
> but I haven't found the need for that yet.

Emilio's example is indeed a good one, and thanks for showing its CL
translation. However, I think that in most cases the single expression
debug is sufficient, and this is indeed doable in C++.

Eli
From: Emilio Lopes
Subject: Re: A "killer" macro
Date: 
Message-ID: <bsr6l2l9kn.fsf@freenet.de>
Raymond Wiker writes:

> Emilio Lopes <·····@gmx.net> writes:

>> Here is my take: a simple macro called `debug', which prints a given
>> *expression* followed by its value.  As a convenience it also returns
>> this same value.

>> [...]

> Not a convincing example of the power of (Lisp) macros; even C++ can
> do this:

> #include <iostream>
> #include <cmath>

> #define DEBUG(a) (std::cerr << "### " << #a << ": " << (a) << std::endl, a)

Does your macro work if the given expression has a side effect, like
in

   int b=41;

   float a = DEBUG(b++);

?

-- 
Em�lio C. Lopes
Munich, Germany
From: Raymond Wiker
Subject: Re: A "killer" macro
Date: 
Message-ID: <m24phyxv2n.fsf@RawMBP.local>
Emilio Lopes <·····@gmx.net> writes:

> Raymond Wiker writes:
>
>> Emilio Lopes <·····@gmx.net> writes:
>
>>> Here is my take: a simple macro called `debug', which prints a given
>>> *expression* followed by its value.  As a convenience it also returns
>>> this same value.
>
>>> [...]
>
>> Not a convincing example of the power of (Lisp) macros; even C++ can
>> do this:
>
>> #include <iostream>
>> #include <cmath>
>
>> #define DEBUG(a) (std::cerr << "### " << #a << ": " << (a) << std::endl, a)
>
> Does your macro work if the given expression has a side effect, like
> in
>
>    int b=41;
>
>    float a = DEBUG(b++);

	Nope... the value is evaluated twice - once for printout, and once
to yield a return value. The "traditional" way to solve this is to
setup a temporary variable to hold the value, which would be tricky to
do with a macro unless we want to restrict orselves to a single
datatype :-)

	It might be possible to do this in an elegant manner with
templates, but I'm a bit fuzzy on the details of templates after to
years of not doing C++ at all (which would be absolutely wonderful if
I could use my preferred programming language instead :-)
From: Raymond Wiker
Subject: Re: A "killer" macro
Date: 
Message-ID: <m2veaewg4x.fsf@RawMBP.local>
Raymond Wiker <···@RawMBP.local> writes:

> 	Nope... the value is evaluated twice - once for printout, and once
> to yield a return value. The "traditional" way to solve this is to
> setup a temporary variable to hold the value, which would be tricky to
> do with a macro unless we want to restrict orselves to a single

                                             ^ ourselves
> datatype :-)
>
> 	It might be possible to do this in an elegant manner with
> templates, but I'm a bit fuzzy on the details of templates after to
                                                                   ^ two

> years of not doing C++ at all (which would be absolutely wonderful if
> I could use my preferred programming language instead :-)

	"I blame my keyboard."(tm)
From: ·············@gmail.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189663542.757173.188420@57g2000hsv.googlegroups.com>
On Sep 12, 2:59 am, Eli Bendersky <······@gmail.com> wrote:
> Hello all,
>
> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.
>
> A longer version: Many contemporary languages boast their sharing most
> of the functional features of Lisp. Perl, Ruby, Javascript - all have
> convenient lists (or arrays), functions as first class objects,
> garbage collection, dynamic typing, lexical closures. However, one
> thing they lack is uniform syntax, and hence the service of a powerful
> built-in macro system such as Common Lisp's "defmacro".
> When confronted by fellow programmers with the question "so why is
> Lisp so special", I'm looking for that short - not too hard to
> understand - snippet of code that will show them *why*. I'm convinced
> that such a snippet must involve macros. But all the examples I ran
> into so far have been either too simple - and could be easily
> implemented another way (for example with Ruby's blocks), or too
> complicated.
>
> Any suggestions for such an example ?
>
> Eli

The "choices sample Logo -> Lisp" discussion might make a nice
example.

The thread left off at:

On Sep 5, 2:00 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> Brian Adkins <···········@gmail.com> writes:
> > I also discovered &optional, so the final version is:
>
> >  (defun choices (menu &optional (sofar '()))
> >   (if menu
> >     (dolist (i (car menu))
> >       (choices (cdr menu) (append sofar (list i))))
> >     (format t "~{~a~^ ~}~%" sofar)))
>
> And if you want to improve the efficiency for longer lists, then using
> the idiom (do they call them design patterns now?) of consing onto the
> front of the list and reversing instead of appending, which I recall
> someone else used.
>
>   (defun choices (menu &optional (sofar '()))
>    ;; This builds up the list in reverse order and then reverses the
>    ;; result just before printing.  Can't use NREVERSE because SOFAR is
>    ;; shared among many branches.
>    (if menu
>      (dolist (i (car menu))
>        (choices (cdr menu) (cons i sofar)))
>      (format t "~{~a~^ ~}~%" (reverse sofar))))
>
> --
> Thomas A. Russ,  USC/Information Sciences Institute

Macros make it pretty easy to extend that solution to make it cover
anything else you might want to do while iterating "choices":

(defmacro dochoices ((choice menu) &body body)
  (let ((choices (gensym))
	(sofar (gensym))
	(inner-menu (gensym))
	(i (gensym)))
    `(labels ((,choices (,inner-menu &optional (,sofar '()))
		(if ,inner-menu
		    (dolist (,i (car ,inner-menu))
		      (,choices (cdr ,inner-menu) (cons ,i ,sofar)))
		    (let ((,choice (reverse ,sofar)))
		      ,@body))))
       (,choices ,menu))))

(defun choices (menu)
  (dochoices (choice menu)
    (format t "~{~a~^ ~}~%" choice)))

Corey
From: fortunatus
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189704927.376050.311080@22g2000hsm.googlegroups.com>
I think we should explore how the same things can be done in other
languages to highlight how it is nicer in Lisp.

A Lisp macro lets one
 a)write a function to write Lisp code at read-time,
 b)allow arguments to the function that include executable code,
 b)in such a way that the macro call looks like normal code.

In other languages, C for instance, this kind of functionality is
done with "pre-processors".  The standard preprocessor fits in a
macro call that looks like a C function call.  The Objective C
preprocessor
writes all kinds of C code and the "macro calls" look like additional
syntax rather than regular C code.

The closest we could come to having a C macro system that is as
nice as the Lisp macro system is to provide a framework for writing
preprocessors.  Such a framework would include a C parser, and a way
to fit the macro call syntax into the parser as either keywords, and/
or
function names, and/or operator syntax, et cetera.

Thinking along these lines, it seems to me that what is nice about
Lisp is this is all pulled together already in the basic language.
The elements include:
 1) the regularized syntax
 2) the reader
 3) defmacro
From: D Herring
Subject: Boost::ScopeExit [Re: A "killer" macro]
Date: 
Message-ID: <o-qdnUny5sjXRXTbnZ2dnUVZ_vCknZ2d@comcast.com>
Eli Bendersky wrote:
> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.

Here's a simple example where code rewriting is almost necessary.

On the Boost developer's list, there was a recent (August 2007) debate 
over a "scope exit" library.  The idea is simple:  intersperse 
exception-handling code inside the function body, and only have it 
execute if the function exits uncleanly.

Here's some C++ code from the author's website.
http://194.6.223.221/~nasonov/scope_exit-0.04/libs/scope_exit/doc/html/scope_exit/tutorial.html

void World::addPerson(Person const& person) {
     bool commit = false;

     m_persons.push_back(person);
     BOOST_SCOPE_EXIT( (commit)(m_persons) )
     {
         if(!commit)
             m_persons.pop_back();
     } BOOST_SCOPE_EXIT_END

     // ... other operations

     commit = true;
}

Explanation:  If "other operations" throw an exception, commit=true 
will be skipped, and the clause in BOOST_SCOPE_EXIT will be triggered.

The problem is in delaying the evaluation of BOOST_SCOPE_EXIT's body 
until the end of the function block.  To do this in C++, an object is 
created; it stores the cleanup code in its destructor.  So the above 
expands to something like

void World::addPerson(Person const& person) {
     bool commit = false;

     m_persons.push_back(person);
     template <class T1, class T2>
     class Guard {
         Guard(T1 &x1, T2 &x2) : commit(x1), m_persons(x2)
         ~Guard() {
         if(!commit)
             m_persons.pop_back();
         }
         T1 &commit;
	T2 &m_persons;
     } guard_variable(commit, m_persons);

     // ... other operations

     commit = true;
}

Several uglinesses appear in this solution.  Among the obvious:
- The variables to be used must be passed explicitely (C++ classes 
nested inside functions cannot see the parent block's variables)
- In general, the variables must be passed "by reference"; an extended 
syntax was proposed to allow something like
   BOOST_SCOPE_EXIT( byref(commit)byval(m_persons) )
- An object is created and values are copied every time this runs -- 
even though the transformation is known at compile time.  A good 
enough compiler _might_ optimize that out.


With a decent macro processor (e.g. Lisp), the story is different.
(defmacro with-scope-guard (&body body)
   "Implement ScopeExit in Lisp"
   (let ((flag nil)
         (normal (list 'progn))
         (guards (list 'progn)))
     (dolist (item body)
       (cond (flag (push item guards)
                   (setf flag nil))
             ((eql item :scope-guard)
              (setf flag t))
             (t (push item normal))))
     (list 'unwind-protect
           (reverse normal)
           (reverse guards))))

(defparameter *people* (list))
(defun guard-test (person)
   "Demonstrate the ScopeExit implementation."
   (let ((commit nil))
     (with-scope-guard
       (push person *people*)
       :scope-guard (unless commit
                      (pop *people*))
       ; ... other operations
       (setf commit t))))

Which macroexpands to something like
(DEFUN GUARD-TEST (PERSON)
   (LET ((COMMIT NIL))
     (UNWIND-PROTECT
       (PROGN
         (PUSH PERSON *PEOPLE*)
         (SETF COMMIT T))
       (PROGN
         (UNLESS COMMIT
           (POP *PEOPLE*))))))

Exactly what we want: no creating lists of variables which need to be 
preserved, no question of how these variables should be passed, and 
minimal runtime overhead.  Plus, since Lisp offers unwind-protect, 
there's no need to manually set the guard variable, commit.


Is that "killer"?  It took me (a relative Lisp noob) all of 5 minutes 
to write (less time than this email) -- well less that what has been 
spent by the collective Boost gurus on their implementation.

- Daniel
From: Rob Warnock
Subject: Re: Boost::ScopeExit [Re: A "killer" macro]
Date: 
Message-ID: <n8SdncOFQcWGnHfbnZ2dnUVZ_vShnZ2d@speakeasy.net>
D Herring  <········@at.tentpost.dot.com> wrote:
+---------------
| (defun guard-test (person)
|    "Demonstrate the ScopeExit implementation."
|    (let ((commit nil))
|      (with-scope-guard
|        (push person *people*)
|        :scope-guard (unless commit
|                       (pop *people*))
|        ; ... other operations
|        (setf commit t))))
| 
| Which macroexpands to something like
| (DEFUN GUARD-TEST (PERSON)
|    (LET ((COMMIT NIL))
|      (UNWIND-PROTECT
|        (PROGN
|          (PUSH PERSON *PEOPLE*)
...        ...[you left out "other operations" here]...
|          (SETF COMMIT T))
|        (PROGN
|          (UNLESS COMMIT
|            (POP *PEOPLE*))))))
| 
| Exactly what we want: no creating lists of variables which need to be 
| preserved, no question of how these variables should be passed, and 
| minimal runtime overhead.  Plus, since Lisp offers unwind-protect, 
| there's no need to manually set the guard variable, commit.
| 
| Is that "killer"?  It took me (a relative Lisp noob) all of 5 minutes 
| to write (less time than this email) -- well less that what has been 
| spent by the collective Boost gurus on their implementation.
+---------------

While this is true -- and congratulations, by the way, nice job! --
I confess that it *doesn't* really seem to meet the bar for a
"killer macro" to me, given that CL already has UNWIND-PROTECT
in the first place. The raw macroexpanded version is just as easy
to write manually than the WITH-SCOPE-GUARD version. (Sorry!)

Slightly easier, actually, since you really don't need the
second PROGN, given the syntax of UNWIND-PROTECT.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: D Herring
Subject: Re: Boost::ScopeExit [Re: A "killer" macro]
Date: 
Message-ID: <dN2dnTB2Wcd2knfbnZ2dnUVZ_iydnZ2d@comcast.com>
Rob Warnock wrote:
> D Herring  <········@at.tentpost.dot.com> wrote:
> +---------------
> | (defun guard-test (person)
> |    "Demonstrate the ScopeExit implementation."
> |    (let ((commit nil))
> |      (with-scope-guard
> |        (push person *people*)
> |        :scope-guard (unless commit
> |                       (pop *people*))
> |        ; ... other operations
> |        (setf commit t))))
> | 
> | Which macroexpands to something like
> | (DEFUN GUARD-TEST (PERSON)
> |    (LET ((COMMIT NIL))
> |      (UNWIND-PROTECT
> |        (PROGN
> |          (PUSH PERSON *PEOPLE*)
> ...        ...[you left out "other operations" here]...
> |          (SETF COMMIT T))
> |        (PROGN
> |          (UNLESS COMMIT
> |            (POP *PEOPLE*))))))
> | 
> | Exactly what we want: no creating lists of variables which need to be 
> | preserved, no question of how these variables should be passed, and 
> | minimal runtime overhead.  Plus, since Lisp offers unwind-protect, 
> | there's no need to manually set the guard variable, commit.
> | 
> | Is that "killer"?  It took me (a relative Lisp noob) all of 5 minutes 
> | to write (less time than this email) -- well less that what has been 
> | spent by the collective Boost gurus on their implementation.
> +---------------
> 
> While this is true -- and congratulations, by the way, nice job! --
> I confess that it *doesn't* really seem to meet the bar for a
> "killer macro" to me, given that CL already has UNWIND-PROTECT
> in the first place. The raw macroexpanded version is just as easy
> to write manually than the WITH-SCOPE-GUARD version. (Sorry!)

No problem.

The point of ScopeExit is to localize the cleanup code with what's 
being cleaned up, and delay evaluation until exit from the entire 
function.  This trivial example doesn't show any benefit -- a 100-line 
function body containing several ScopeExits might be another story. 
In that case, a raw unwind-protect might put 50 lines between the 
action and its conditional cleanup.

This is a real-world example where a short Lisp macro easily solves a 
difficult C++ problem.  The corresponding C++ code is much longer and 
harder to follow.  Whether this qualifies as "killer" doesn't really 
matter much (I already have a language preference).


 > Slightly easier, actually, since you really don't need the
 > second PROGN, given the syntax of UNWIND-PROTECT.

The second progn is there to handle multiple :scope-guard clauses. 
What's missing is a gensym to auto-generate the "complete" flag that 
conditions the execution of :scope-cleanup clauses.

- Daniel
From: Rob Warnock
Subject: Re: Boost::ScopeExit [Re: A "killer" macro]
Date: 
Message-ID: <gcSdnTH3arISiHfbnZ2dnUVZ_sGvnZ2d@speakeasy.net>
D Herring  <········@at.tentpost.dot.com> wrote:
+---------------
| Rob Warnock wrote:
| > ...[elided]...
| 
| The point of ScopeExit is to localize the cleanup code with what's 
| being cleaned up, and delay evaluation until exit from the entire 
| function.  This trivial example doesn't show any benefit -- a 100-line 
| function body containing several ScopeExits might be another story. 
| In that case, a raw unwind-protect might put 50 lines between the 
| action and its conditional cleanup.
+---------------

Aha! yes, I'd overlooked that part of it. You're correct.

+---------------
| > Slightly easier, actually, since you really don't need the
| > second PROGN, given the syntax of UNWIND-PROTECT.
| 
| The second progn is there to handle multiple :scope-guard clauses. 
+---------------

My point was just that UNWIND-PROTECT already accepts multiple
forms in the cleanup section, so the second PROGN is redundant.
You can just ",@" the list of cleanup forms directly into the
UNWIND-PROTECT being generated.

+---------------
| What's missing is a gensym to auto-generate the "complete" flag
| that conditions the execution of :scope-cleanup clauses.
+---------------

What would be useful is to be able to name each of the ScopeExits,
and then MACROLET a COMMIT macro that takes a name that maps to
the correct LET-bound GENSYM'd boolean. That is, something like:

    (with-scope-exits
       ...stuff...
       (scope-exit (foo)
	  ...stuff-to-do-for-foo-chunk...
	  ...rollback-forms-for-foo-chunk...)
       ...more-stuff...
       (commit foo)
       ...even-more-stuff...)

So at the beginning WITH-SCOPE-EXITS would "(LET ((#:G123 nil) ...) ..."
[where #:G123 is the GENSYM the macro assigned to FOO], and then
the (COMMIT FOO) would expand to (SETF #:G123 T), and then one
of the cleanup forms for the UNWIND-PROTECT would be:

        (unless #:G123
	  ...rollback-forms-for-foo-chunk...)

Is that what you're talking about?


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: D Herring
Subject: Re: Boost::ScopeExit [Re: A "killer" macro]
Date: 
Message-ID: <su6dnRI5SoX0j3fbnZ2dnUVZ_jidnZ2d@comcast.com>
D Herring wrote:
> Rob Warnock wrote:
>> D Herring  <········@at.tentpost.dot.com> wrote:
>> +---------------
>> | (defun guard-test (person)
>> |    "Demonstrate the ScopeExit implementation."
>> |    (let ((commit nil))
>> |      (with-scope-guard
>> |        (push person *people*)
>> |        :scope-guard (unless commit
>> |                       (pop *people*))
>> |        ; ... other operations
>> |        (setf commit t))))
>> | | Which macroexpands to something like
>> | (DEFUN GUARD-TEST (PERSON)
>> |    (LET ((COMMIT NIL))
>> |      (UNWIND-PROTECT
>> |        (PROGN
>> |          (PUSH PERSON *PEOPLE*)
>> ...        ...[you left out "other operations" here]...
>> |          (SETF COMMIT T))
>> |        (PROGN
>> |          (UNLESS COMMIT
>> |            (POP *PEOPLE*))))))
>> +---------------
>  > ... you really don't need the
>  > second PROGN, given the syntax of UNWIND-PROTECT.
> 
> The second progn is there to handle multiple :scope-guard clauses. 

Drrb.  Noob-alert.

CLHS syntax:
(unwind-protect protected-form cleanup-form*) => result*

Now I get it.

Thanks,
Daniel
From: ··········@aol.com
Subject: Re: A "killer" macro
Date: 
Message-ID: <1189995702.417888.63890@r29g2000hsg.googlegroups.com>
On Sep 12, 2:59 am, Eli Bendersky <······@gmail.com> wrote:
> Hello all,
>
> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.

I don't think such a thing exists, in the context (evangelism) that
you want it. There are plenty of killers out there, but any of them
could be included as a feature in another language, or simulated
(probably clumsily) in almost any language. The "killer" macro, in CL
is that you can write your own macros, not any particular macro. If
you are really interested in evangelism (I'm not, except to the
already receptive), that is the point about macros that must be driven
home, and even simple macros can serve that purpose- they might even
be better for that purpose than more complex macros, as your audience
is more likely to understand the mechanism, instead of pointing out
equivalent feature X in their pet language, or getting bogged down in
the swamp of Turing equivalence.

> A longer version: Many contemporary languages boast their sharing most
> of the functional features of Lisp. Perl, Ruby, Javascript - all have
> convenient lists (or arrays), functions as first class objects,
> garbage collection, dynamic typing, lexical closures. However, one
> thing they lack is uniform syntax, and hence the service of a powerful
> built-in macro system such as Common Lisp's "defmacro".
> When confronted by fellow programmers with the question "so why is
> Lisp so special",

The answer to that is not, IMHO, one killer macro, nor is it CL's
macro facility, in isolation. If you push a "killer" macro as CL's
strong point you just invite people to show that that macro can be
mimicked in some other language. In the worst case their pet language
was explicitly designed to do what your "killer" macro does, and does
that one thing more elegantly... that is called "having been
'Harroped'". Anyone can be Harroped, so be careful out there. It's
embarrassing _and_ unsightly- and there is evidence that it is
contagious[1].

>I'm looking for that short - not too hard to
> understand - snippet of code that will show them *why*. I'm convinced
> that such a snippet must involve macros. But all the examples I ran
> into so far have been either too simple - and could be easily
> implemented another way (for example with Ruby's blocks), or too
> complicated.

Anything really simple in CL will have a reasonably simple expression
in some other language. For that matter, anything that is truly simple
in CL is likely not impossibly difficult in some macro-equipped
assembler.  What gets missed here is that developing it will be, at
least for me, much more pleasant in CL. I think that is the point to
hammer home, if you are interested in CL evangelism. Real programming,
like anything else worth doing (leaving aside things like sex, skiing,
and eating ice cream), is at times very painful- painful enough to
leave you wondering if you should have been a sex instructor, or
pimped some skiers to the highest bidder... anything that makes it
less painful will be welcomed, if the reduction in pain can be shown
to be greater than the pain of adjusting to a new environment added to
the pain of giving up preconceptions.

The problem is that it is not one feature of Lisp that makes Lisp more
pleasant to me. It is the interaction of many of CL's features that
makes it attractive. Actually, it is the way that I develop in CL that
I value- I only value CL's features because they make that development
style  possible. This is where you go wrong, I think- you are trying
to sell  features, in the abstract, instead of selling value. You are
also selling steak instead of sizzle, but that is, while related, not
quite the same thing.

> Any suggestions for such an example ?

I'm not that interested in Lisp evangelism in the large, but I've done
a lot of it in the small, and I think that that may be of more value,
in the end, than public bickering over whether Python or Ruby (or even
Scheme) is an "acceptable Lisp".  The only way I can show someone why
I like CL (and, by extension, why they should) is to sit down with
them and write a simple, but interesting program. I don't usually
define macros when I do this, as I'm often sitting down with
programmers who need to be coached into recursing on cdrs, and have
never even seen a real tree, let alone figured out how to traverse it.
I just try to show them how some subset of features interacts to make
a pleasant development experience, preferably with a problem they
would find difficult to solve in their normal environment. I have this
down to "patter" at this point, but that patter is derived from real
problems I have had to solve

I don't think you can show why it is nicer to develop in CL than in X
environment by displaying a macro. I also think it is hard to pry
people away from their favorite language, if it is any good at all-
the harder you try, the harder it becomes. I'd rather concentrate on
the VB programmers I know than on the Python programmers I don't- and
I do that for their sake, not Lisp's.

If you really want to evangelize CL, in the large, I see three ways to
do it, in order of preference:
   1) start a business that requires and allows you to hire CL
programmers (i.e. money, mouth)
   2) personally teach people who really need help- the above VB
programmers, who will be receptive to anything that makes the pain go
away for a minute
   3) libraries

Dick length comparison with good [insert language here] programmers
via "killer" macros ranks 4th, rather than 101st, only because I do
not enumerate 4-100. The only thing you will get out of that is an
explanation of how to do what your killer macro does in language X-
that might be educational, but it's unlikely to serve your purpose.
From: Leandro Rios
Subject: Re: A "killer" macro
Date: 
Message-ID: <46ee8ff9$0$1346$834e42db@reader.greatnowhere.com>
··········@aol.com escribi�:

[snip]

>    2) personally teach people who really need help- the above VB
> programmers, who will be receptive to anything that makes the pain go
> away for a minute

Man, you really know what are you talking about. As a VB programmer 
halfway through his conversion path, I can only agree with what you 
said. Maybe that should be CL's main selling point: "Common Lisp: Eases 
the pain!"

Leandro
From: Ken Tilton
Subject: Re: A "killer" macro
Date: 
Message-ID: <QRxHi.59$iA.3@newsfe12.lga>
Leandro Rios wrote:
> ··········@aol.com escribi�:
> 
> [snip]
> 
>>    2) personally teach people who really need help- the above VB
>> programmers, who will be receptive to anything that makes the pain go
>> away for a minute
> 
> 
> Man, you really know what are you talking about. As a VB programmer 
> halfway through his conversion path, I can only agree with what you 
> said. Maybe that should be CL's main selling point: "Common Lisp: Eases 
> the pain!"
> 

Did you know you were in pain before you learned CL? The RtL subsection 
(name forgotten) for Seek-and-ye-shall-find is not very big. Pythonistas 
thought they were in pig heaven until Ruby went upside their heads. Java 
might be an interesting case, a language that even its advocates hate.

The question is, When Steele and Norvig come running back to Lisp, do we 
let them back in? What about the Scheme Insurrection? Amnesty for them, 
or do we go with plan A and just lop off their heads?

We're gonna need more hounds.

kt

-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut
From: Leandro Rios
Subject: Re: A "killer" macro
Date: 
Message-ID: <46efc67b$0$1348$834e42db@reader.greatnowhere.com>
Ken Tilton escribi�:

> Did you know you were in pain before you learned CL? The RtL subsection 
> (name forgotten) for Seek-and-ye-shall-find is not very big. 

Yes, I did. That was one of the motivations for my Quest for a Better
Language. The other one was the non trivial fact that Microsoft decided
that VB was over, leaving all of the vb programmers wondering what to do
with their (sometimes big) codebase.

So I was looking for an industrial strength, standarized, and powerful
language. One with a free implementation, and with a supporting
community. Multiplatform, so I won't be depending on MS Windows.

And here I am. Still learning, but very comfortable with the language.

I find the accumulation of knowledge and expertise over the past 50
years just invaluable. Very smart people accumulated thousands of high
quality man-months into doing (Common) Lisp what is now. I find it very 
important that the implementations of the language must adhere to the 
spec in order to be called "ANSI Common Lisp". I find comforting that 
the people hanging in c.l.l are always ready to answer any kind of 
questions, from newbie-kind to highly technical/theoretical or 
historical (This is a language with a lot of history behind!). c.l.l. 
answered a lot of my questions (and keeps answering) even when I didn't 
ask a single one, because Google is my friend :) ; and I must say I'm 
really grateful to you all (I can hear the hounds coming...)

I had to learn and re-learn a lot of things and I had to change my 
mindset about programming. That was the hardest part. The learning curve 
was steeper than I thought, but I recovered the programming fun. 
Programming was becoming a boring and tedious task, and now I enjoy it 
again, even when I have to do it in VB.

If you ask me, I don't believe this can be properly conveyed to someone 
else via some "killer macro". As sharpquote said, it's some "coaching" 
what is needed.

Leandro
From: =?utf-8?b?R2lzbGUgU8ODwqZsZW5zbWk=?= =?utf-8?b?bmRl?=
Subject: Re: A "killer" macro
Date: 
Message-ID: <0nve9z9nys.fsf@kaktus.ii.uib.no>
Eli Bendersky <······@gmail.com> writes:

> Hello all,
> 
> In short: I'm looking for a "killer" macro - a macro (or a couple of
> related ones) that show what Lisp can do and other languages (those
> without uniform syntax) can not.
> 
> A longer version: Many contemporary languages boast their sharing most
> of the functional features of Lisp. Perl, Ruby, Javascript - all have
> convenient lists (or arrays), functions as first class objects,
> garbage collection, dynamic typing, lexical closures. However, one
> thing they lack is uniform syntax, and hence the service of a powerful
> built-in macro system such as Common Lisp's "defmacro".
> When confronted by fellow programmers with the question "so why is
> Lisp so special", I'm looking for that short - not too hard to
> understand - snippet of code that will show them *why*. I'm convinced
> that such a snippet must involve macros. But all the examples I ran
> into so far have been either too simple - and could be easily
> implemented another way (for example with Ruby's blocks), or too
> complicated.
> 
> Any suggestions for such an example ?

I have earlier used an implementation of a lexer macro as an example, see
http://groups.google.no/group/comp.lang.lisp/browse_thread/thread/2d7e3fc62d5cfdbc/a1068634fe42c048?lnk=st&q=darwin-lex&rnum=3#a1068634fe42c048

(Page show just usage, not the implementation, I can post that if you want)
In most languages, the equivalent is an external tool that macine-generate code.
There is also cl-yacc, that define a similar

Another, and a really good example if you are less into compilers and it's tools, 
is the binary file macros in Peter Seibels Practical common lisp (chapter 24), 
and available online. This is a really good example of good macro usage:

http://www.gigamonkeys.com/book/practical-parsing-binary-files.html


-- 
Gisle Sælensminde, Phd student, Scientific programmer
Computational biology unit, BCCS, University of Bergen, Norway, 
Email: ·····@cbu.uib.no
The best way to travel is by means of imagination
From: Alan Walker
Subject: Re: A "killer" macro
Date: 
Message-ID: <%wEKi.6973$f%1.2067@trnddc01>
How about a "killer macro" that makes you want to kill the author?

A couple of years ago I was mucking around with ideas to run IBM mainframe
assembler code on my PC.  You define the opcodes like this:

    ;; Register to register add
    (defmacro _ar (x1 x2)
       `(setf (,x1 *cpu*) (+ (,x1 *cpu*) (,x2 *cpu*))))

    ;; Unconditional branch
    (defmacro _b (label)
       `(go ,label))

Then, you can quickly translate the assembler code to a string:

    (setf fn-str
      " (lambda (*cpu*)
      (tagbody ; segment
            (_set r1 60000000)  ; loop counter i
            (_set r2 1)    ; a
            (_set r3 1)    ; b
        top (_lr  r4 r2)   ; c = a
            (_ar  r4 r3)   ; c += b
            (_lr  r2 r3)   ; a = b
            (_lr  r3 r4)   ; b = c
            (_addi r1 -1)  ; --i
            (_c    r1 0)   ; is i == 0?
            (_bct   top)
           (go segment-end)
        segment-end)
       )
     "
    )

Now, all you have to do is compile it and you have a home-grown JIT for
mainframe programs:

    (compile fn (read-from-string fn-str))

This actually runs pretty fast.  Allegro CL generated about twice as many
opcodes (x86) as the original mainframe opcodes, and my PC is much cheaper
than a mainframe as it was assembled from parts I bought at Frys.

Alan.

"Gisle Sælensminde" <·····@kaktus.ii.uib.no> wrote in message
···················@kaktus.ii.uib.no...
> Eli Bendersky <······@gmail.com> writes:
>
> > Hello all,
> >
> > In short: I'm looking for a "killer" macro - a macro (or a couple of
> > related ones) that show what Lisp can do and other languages (those
> > without uniform syntax) can not.
> >
> > A longer version: Many contemporary languages boast their sharing most
> > of the functional features of Lisp. Perl, Ruby, Javascript - all have
> > convenient lists (or arrays), functions as first class objects,
> > garbage collection, dynamic typing, lexical closures. However, one
> > thing they lack is uniform syntax, and hence the service of a powerful
> > built-in macro system such as Common Lisp's "defmacro".
> > When confronted by fellow programmers with the question "so why is
> > Lisp so special", I'm looking for that short - not too hard to
> > understand - snippet of code that will show them *why*. I'm convinced
> > that such a snippet must involve macros. But all the examples I ran
> > into so far have been either too simple - and could be easily
> > implemented another way (for example with Ruby's blocks), or too
> > complicated.
> >
> > Any suggestions for such an example ?
>
> I have earlier used an implementation of a lexer macro as an example, see
>
http://groups.google.no/group/comp.lang.lisp/browse_thread/thread/2d7e3fc62d5cfdbc/a1068634fe42c048?lnk=st&q=darwin-lex&rnum=3#a1068634fe42c048
>
> (Page show just usage, not the implementation, I can post that if you
want)
> In most languages, the equivalent is an external tool that macine-generate
code.
> There is also cl-yacc, that define a similar
>
> Another, and a really good example if you are less into compilers and it's
tools,
> is the binary file macros in Peter Seibels Practical common lisp (chapter
24),
> and available online. This is a really good example of good macro usage:
>
> http://www.gigamonkeys.com/book/practical-parsing-binary-files.html
>
>
> -- 
> Gisle S�lensminde, Phd student, Scientific programmer
> Computational biology unit, BCCS, University of Bergen, Norway,
> Email: ·····@cbu.uib.no
> The best way to travel is by means of imagination
From: Ken Tilton
Subject: Re: A "killer" macro
Date: 
Message-ID: <ogGKi.744$fT2.329@newsfe12.lga>
Alan Walker wrote:
> How about a "killer macro" that makes you want to kill the author?

Excellent point. More than once I have been moved to drag my butt out of 
my chair and physically invade neighboring cubicles to demand 
satisfaction from authors, though in the primitive languages encountered 
in tall buildings the offense was usually a name of a variable.

kt

-- 
http://www.theoryyalgebra.com/

"We are what we pretend to be." -Kurt Vonnegut