From: Tayssir John Gabbour
Subject: Dredging up patterns
Date: 
Message-ID: <866764be.0405250036.2142d52d@posting.google.com>
Has anyone really thought about "patterns" in lisp's context? By that
I mean that whole Christopher Alexander thing Gabriel writes about in
_Patterns of Software_.
http://www.dreamsongs.com/NewFiles/PatternsOfSoftware.pdf

On one hand, when I see normal patterns from other communities, I
think they're overintellectualized ways of getting around artificial
language problems. However, Gabriel describes the Hillside Group,
which met and talked about patterns which solve problems they
encounter. And maybe the point is about being a good pedagogy tool,
some semistructure to frame thoughts in.


Pattern: Let user decide tradeoffs.
Problem: You're faced with a tradeoff which requires knowledge of user
needs to competently make.
Constraints: You have a few years to blow finding where to open the
implementation.
Examples:
- %stuff in Lisp Machines you can redefine
- metaobject protocol

Pattern: Mess with lexical/dynamic scope.
Problem: You want to interact with the stack without actually moving
along it.
Examples: conditions system

Pattern: Don't use macros.
Problem: Ever try to mapcar over a macro in Common Lisp?
Solution: Certain jaded outlook.


I think standards are really apropos to patterns, with the theme of
well-trod paths.

Also, the "Don't use macros" pattern above actually was from Ernst van
Waning's recent Amsterdam talk. I think I messed up the writeup
because he used the term "smell," which is used in that patterns
community, and I didn't consider attempting to write it up from the
patterns perspective.
http://alu.cliki.net/lisp-user-meeting-amsterdam-april-2004

From: Laurence Kramer
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c8vr7a$6vh$1@wolfberry.srv.cs.cmu.edu>
Tayssir John Gabbour wrote:

> Has anyone really thought about "patterns" in lisp's context? By that
> I mean that whole Christopher Alexander thing Gabriel writes about in
> _Patterns of Software_.
> http://www.dreamsongs.com/NewFiles/PatternsOfSoftware.pdf

Peter Norvig has given it some thought --
http://norvig.com/design-patterns/ppframe.htm --
and found that 16 of 23 "standard" patterns are simpler or invisible in
Dylan or Lisp due to: First class types, first class functions, macros,
method combination, multimethods, and modules.

Larry
From: Pascal Costanza
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c908g2$k70$1@newsreader2.netcologne.de>
Laurence Kramer wrote:

> Tayssir John Gabbour wrote:
> 
>> Has anyone really thought about "patterns" in lisp's context? By that
>> I mean that whole Christopher Alexander thing Gabriel writes about in
>> _Patterns of Software_.
>> http://www.dreamsongs.com/NewFiles/PatternsOfSoftware.pdf
> 
> Peter Norvig has given it some thought --
> http://norvig.com/design-patterns/ppframe.htm --
> and found that 16 of 23 "standard" patterns are simpler or invisible in
> Dylan or Lisp due to: First class types, first class functions, macros,
> method combination, multimethods, and modules.

It's a pity that the book by Gamma et al. has stifled the useful notions 
of patterns. Those 23 "standard" patterns represent really just a tiny 
fraction of what patterns could mean.

What's really more important, IMHO, is the notion of forces. The fact 
that the GoF patterns (those 23 patterns) are considered patterns is 
caused by the fact that the languages they are implemented in are too 
limited - in other words, the limitations of the languages turn into 
restricting forces, and then indeed patterns are needed to resolve those 
forces. These patterns "disappear" in other languages just because those 
forces don't exist there.

But this doesn't mean that the notion of patterns is useless. This would 
be like saying that algorithms are useless because Common Lisp has SORT 
and STABLE-SORT.

A good starting point for patterns is 
http://www.bradapp.net/docs/patterns-intro.html


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: mrd
Subject: Re: Dredging up patterns
Date: 
Message-ID: <Pine.LNX.4.58-035.0405251346200.4646@unix45.andrew.cmu.edu>
On Tue, 25 May 2004, Tayssir John Gabbour wrote:
> Pattern: Don't use macros.
> Problem: Ever try to mapcar over a macro in Common Lisp?
> Solution: Certain jaded outlook.

If you by patterns you mean "patterns of newbies" then yes, "trying to use
mapcar over a macro in CL" demonstrates a serious and fundamental
misunderstanding of the nature of macros.
From: Simon Adameit
Subject: Re: Dredging up patterns
Date: 
Message-ID: <pan.2004.05.25.18.24.55.663481@gmx.net>
Am Tue, 25 May 2004 14:53:33 -0400 schrieb mrd:

> On Tue, 25 May 2004, Tayssir John Gabbour wrote:
>> Pattern: Don't use macros.
>> Problem: Ever try to mapcar over a macro in Common Lisp?
>> Solution: Certain jaded outlook.
> 
> If you by patterns you mean "patterns of newbies" then yes, "trying to use
> mapcar over a macro in CL" demonstrates a serious and fundamental
> misunderstanding of the nature of macros.

Does it? I think it's just a limitation of lisp's macros that they cant be
passed around and not inherent in the macro concept. Though it would
probably be terrebly inefficient and need access to the lexical
environment to expand them at runtime.
From: mrd
Subject: Re: Dredging up patterns
Date: 
Message-ID: <Pine.LNX.4.58-035.0405251600320.5802@unix45.andrew.cmu.edu>
On Tue, 25 May 2004, Simon Adameit wrote:
> Am Tue, 25 May 2004 14:53:33 -0400 schrieb mrd:
>
> > On Tue, 25 May 2004, Tayssir John Gabbour wrote:
> >> Pattern: Don't use macros.
> >> Problem: Ever try to mapcar over a macro in Common Lisp?
> >> Solution: Certain jaded outlook.
> >
> > If you by patterns you mean "patterns of newbies" then yes, "trying to use
> > mapcar over a macro in CL" demonstrates a serious and fundamental
> > misunderstanding of the nature of macros.
>
> Does it? I think it's just a limitation of lisp's macros that they cant be
> passed around and not inherent in the macro concept. Though it would
> probably be terrebly inefficient and need access to the lexical
> environment to expand them at runtime.

In short, the macro is a computation meant to run at compile-time, meant
to operate on source code.  What is the meaning of a macro operating on
run-time values?

Consider (mapcar 'macro (list 1 2 3)).  You are asking that a
compile-time computation be applied to the run-time list value (1 2 3).
What then, is the difference from a function?

Or perhaps that it be applied to the compile-time source code list value
(list 1 2 3).  Yet macro functions are supposed to return valid lisp
forms; what could this macro return that would be valid when fed to the
compiler?

(defmacro macro (x) x)

Not terribly useful, it cannot return compound forms.  And if this code
is executed outside the context of the compiler, then what use is it?  You
have a piece of source code now, that needs to be evaluated.  But if your
ultimate aim was the source code itself, then why are you using a macro at
run-time?  That's what functions are for.
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyfk6yzl6xm.fsf@pcepsft001.cern.ch>
mrd <·······@andrew.cmu.edu> writes:

> In short, the macro is a computation meant to run at compile-time, meant
> to operate on source code.

Yes, but there is no way of distinguishing a macro from a function by
analysys of the call point. The user does not (necessarily) know
whether the thing he is calling is a function or a macro. It being a
macro could be an implementation detail:

(defun average (&rest rest)
  (/ (reduce #'+ rest)
     (length rest)))

(defmacro average (&body body)
  `(/ (reduce #'+ ',body)
      ,(length body)))

> What is the meaning of a macro operating on run-time values?

This shouldn't be such an alien concept: when working interactively,
at the REPL, we keep calling macros at runtime. In Lisp, there is no
strict ordering and separation of macro expansion time -> compile time
-> run time, such as one finds in less flexible languages.

For example what if I want to create a new class at runtime based on
some information I calculate[*]? I would like to be able to "call"
defclass at runtime, passing it some data which was not available
until runtime. As a user of defclass, I do not care that is a macro,
to me it is "that which creates classes" and "that which creates
classes" happens to be what I need right now, at runtime.

> Consider (mapcar 'macro (list 1 2 3)).  You are asking that a
> compile-time computation be applied to the run-time list value (1 2 3).
> What then, is the difference from a function?

That is a question you would have to ask the implementor, not the
user.

> Or perhaps that it be applied to the compile-time source code list value
> (list 1 2 3).  Yet macro functions are supposed to return valid lisp
> forms; what could this macro return that would be valid when fed to the
> compiler?

As a user, I do not care. But I would hope that the final result is
equivalent to

(list (macro 1) (macro 2) (macro 3))

Macros are indistiguishable from functions at the call site, the
question is "how far can we push the luxury of ignorance about their
true nature?"


[*] I'm working on a project which aims to reflect C++ classes in
    another language (unfortunately not Lisp) by inspecting header
    files, and creating proxy classes in the other language. So
    creating classes at runtime IS a real-world example.
From: mrd
Subject: Re: Dredging up patterns
Date: 
Message-ID: <Pine.LNX.4.58-035.0405261013290.1862@unix45.andrew.cmu.edu>
On Wed, 26 May 2004, Jacek Generowicz wrote:
> mrd <·······@andrew.cmu.edu> writes:
>
> > In short, the macro is a computation meant to run at compile-time, meant
> > to operate on source code.
>
> Yes, but there is no way of distinguishing a macro from a function by
> analysys of the call point. The user does not (necessarily) know
> whether the thing he is calling is a function or a macro. It being a
> macro could be an implementation detail:

It is more than an implementational detail; macros and functions are not
for expressing the same thing, even though there are a few areas where
they seem to coincide.

And your IDE should tell you which one a name is, too.

> (defun average (&rest rest)
>   (/ (reduce #'+ rest)
>      (length rest)))
>
> (defmacro average (&body body)
>   `(/ (reduce #'+ ',body)
>       ,(length body)))

These have different semantics.  Try (average x y z).

> > What is the meaning of a macro operating on run-time values?
>
> This shouldn't be such an alien concept: when working interactively,
> at the REPL, we keep calling macros at runtime. In Lisp, there is no
> strict ordering and separation of macro expansion time -> compile time
> -> run time, such as one finds in less flexible languages.

In Lisp, no.  For Lisp code, yes, there is a distinct "read-time",
"macroexpansion-time", "compile-time", "load-time", and "eval-time".
Macros are all expanded by or at the time the evaluator gets to them.

> For example what if I want to create a new class at runtime based on
> some information I calculate[*]? I would like to be able to "call"
> defclass at runtime, passing it some data which was not available
> until runtime. As a user of defclass, I do not care that is a macro,
> to me it is "that which creates classes" and "that which creates
> classes" happens to be what I need right now, at runtime.

And the invocation of defclass is expanded into some specific code that is
evaluated at run-time.  Defclass itself is long gone.

> > Or perhaps that it be applied to the compile-time source code list value
> > (list 1 2 3).  Yet macro functions are supposed to return valid lisp
> > forms; what could this macro return that would be valid when fed to the
> > compiler?
>
> As a user, I do not care. But I would hope that the final result is
> equivalent to
>
> (list (macro 1) (macro 2) (macro 3))

I would expect ((macro list) (macro 1) (macro 2) (macro 3)) but yours is
an interesting interpretation as well, though maybe for different reasons
than you originally thought?

> Macros are indistiguishable from functions at the call site, the
> question is "how far can we push the luxury of ignorance about their
> true nature?"

This is an artifact of the simplicity of the Lisp syntax.  The system
knows the difference through environmental information.

> [*] I'm working on a project which aims to reflect C++ classes in
>     another language (unfortunately not Lisp) by inspecting header
>     files, and creating proxy classes in the other language. So
>     creating classes at runtime IS a real-world example.

This is not in dispute.
From: Lars Brinkhoff
Subject: Re: Dredging up patterns
Date: 
Message-ID: <85smdnp78s.fsf@junk.nocrew.org>
mrd <·······@andrew.cmu.edu> wrote:
> Jacek Generowicz wrote:
> > mrd <·······@andrew.cmu.edu> wrote:
> > > Consider (mapcar 'macro (list 1 2 3))
> >
> > I would hope that the final result is equivalent to
> > (list (macro 1) (macro 2) (macro 3))
> 
> I would expect ((macro list) (macro 1) (macro 2) (macro 3)) but
> yours is an interesting interpretation as well

I would find Jacek's interpretation least surprising.  I don't think
it would be unreasonable to rearrange the mapcar expression into
something like

        (let ((fn (lambda (x) (eval `(macro ,x)))))
          (mapcar fn (list 1 2 3)))

-- 
Lars Brinkhoff,         Services for Unix, Linux, GCC, HTTP
Brinkhoff Consulting    http://www.brinkhoff.se/
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyf3c5ml4ze.fsf@pcepsft001.cern.ch>
mrd <·······@andrew.cmu.edu> writes:

[ (mapcar 'macro (list 1 2 3)) ]

> > As a user, I do not care. But I would hope that the final result is
> > equivalent to
> >
> > (list (macro 1) (macro 2) (macro 3))
> 
> I would expect ((macro list) (macro 1) (macro 2) (macro 3))

Wow, that surprised me at first ... but I see where you are coming from.

> but yours is an interesting interpretation as well, though maybe for
> different reasons than you originally thought?

Care to expand ?

> > Macros are indistiguishable from functions at the call site, the
> > question is "how far can we push the luxury of ignorance about their
> > true nature?"
> 
> This is an artifact of the simplicity of the Lisp syntax.  The system
> knows the difference through environmental information.

I don't dispute that the system knows the difference. What I am
questioning is the extent to which the client programmer does or
should know the difference. Maybe this touches an area of (Common)
Lisp philosophy in which I am not versed. (Quite likely.)
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87k6yqpnm3.fsf@nyct.net>
Jacek Generowicz <················@cern.ch> writes:

> I don't dispute that the system knows the difference. What I am
> questioning is the extent to which the client programmer does or
> should know the difference. Maybe this touches an area of (Common)
> Lisp philosophy in which I am not versed. (Quite likely.)

It's not really philosophy of any language. It's the philosophy that
you're supposed to know the interface for an operator BEFORE you try to
use it. In Lisp, macros are one class of interface and functions are
another.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: ·········@random-state.net
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c92aug$bk75g$1@midnight.cs.hut.fi>
Jacek Generowicz <················@cern.ch> wrote:

> whether the thing he is calling is a function or a macro. It being a
> macro could be an implementation detail:

> (defun average (&rest rest)
>   (/ (reduce #'+ rest)
>      (length rest)))

> (defmacro average (&body body)
>   `(/ (reduce #'+ ',body)
>       ,(length body)))

Nononono! It hurts, please stop!

This is the classic example of where you should *not* use a macro. If you
need the compile-time optimizations use inline declarations and
compiler-macros -- and complain to your implementor if they don't work.

Now pick up the chalk and write 100 times on the blackboard: 

 "I shall not use macros as an optimization tool, nor shall I ever write a
 macro that could be expressed equally well as a function or so help me
 god."

If you want macros that you can apply have a look at older lisps: it was
ways before my time, but I believe all the wierd function variants that
did or didn't evaluate their arguments were dropped for a good reason.

If you want to create classes at runtime, use the correct interface: MOP.

If you want to do X and the only interface to do it is via macros complain
to the implementor of that interface. Functional primitives should
generally be provided in addition to a declarative macro-powered
interface.

Cheers,

  -- Nikodemus
From: Duane Rettig
Subject: Re: Dredging up patterns
Date: 
Message-ID: <4n03v5f7d.fsf@franz.com>
·········@random-state.net writes:

> Jacek Generowicz <················@cern.ch> wrote:
> 
> > whether the thing he is calling is a function or a macro. It being a
> > macro could be an implementation detail:
> 
> > (defun average (&rest rest)
> >   (/ (reduce #'+ rest)
> >      (length rest)))
> 
> > (defmacro average (&body body)
> >   `(/ (reduce #'+ ',body)
> >       ,(length body)))
> 
> Nononono! It hurts, please stop!

Yesyesyes!  Don't stop; to remove the hurting, just fix the bug.

> This is the classic example of where you should *not* use a macro. If you
> need the compile-time optimizations use inline declarations and
> compiler-macros -- and complain to your implementor if they don't work.
> 
> Now pick up the chalk and write 100 times on the blackboard: 
> 
>  "I shall not use macros as an optimization tool, nor shall I ever write a
>  macro that could be expressed equally well as a function or so help me
>  god."

I snap your chalk in two, sir!  :-)

As a general rule, I avoid making general rules.  This general rule
is especially pernicious, because it makes maxims out of rules that are
not stated or even implied in the Common Lisp spec or its tradition.

For example, even apart from defining macros, which have obvious needs
for exposure of the implementation for eval-when purposes, there are
a number of macros used as interface functions, (e.g. loop, trace, etc),
and there are a number of reasons to use macros (including
compiler-macros) to effect optimizations.

The usage of macros (and your maxim) can be paralleled to the use of GO;
many times people have uttered those maxims "never use goto" but the fact
remains that most languages provide them, and for good reason.  The usage
of each language feature must always be steeped in the wisdom of their best
application, and precluding the use of a language feature unconditionally
is at best naiive, and at worst repressive.

> If you want macros that you can apply have a look at older lisps: it was
> ways before my time, but I believe all the wierd function variants that
> did or didn't evaluate their arguments were dropped for a good reason.
> 
> If you want to create classes at runtime, use the correct interface: MOP.

The MOP is not standard, nor is it necessary to create classes at
runtime.

> If you want to do X and the only interface to do it is via macros complain
> to the implementor of that interface.

I think if you follow this advice you will be frustrated.

> Functional primitives should
> generally be provided in addition to a declarative macro-powered
> interface.

I do actually agree in general that the best interfaces that include
macros will also provide a function-based interface, but it is not
necessary, nor should it be a requirement.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: ·········@random-state.net
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c92mg7$bf6su$1@midnight.cs.hut.fi>
Duane Rettig <·····@franz.com> wrote:

>> This is the classic example of where you should *not* use a macro. If you
>> need the compile-time optimizations use inline declarations and
>> compiler-macros -- and complain to your implementor if they don't work.
>> 
>> Now pick up the chalk and write 100 times on the blackboard: 
>> 
>>  "I shall not use macros as an optimization tool, nor shall I ever write a
>>  macro that could be expressed equally well as a function or so help me
>>  god."

> I snap your chalk in two, sir!  :-)

Hehee. ,-)

> As a general rule, I avoid making general rules.  This general rule
> is especially pernicious, because it makes maxims out of rules that are
> not stated or even implied in the Common Lisp spec or its tradition.

Ok. Somehow I've the feeling that you don't agree with the following
statements either, however:

 "Using macros for optimization instead of inline declarations
  and compiler macros is good practise."

 "Writing macros when the same interface can be expressed as a
  function is good practice."

I certainly don't.

(As you note I was a bit more careful in qualifying these ones, and in
spirit of historical revisionism apply similar qualification to my
original guideline. Specifically I'm advocating against macros which could
be equally well realized, with the same look and feel, as functions
accompanied by compiler-macros or inline declarations.)

Furthermore, I'm not sure whether I expressed my intention in a horribly
muddled manner, or what, since I find myself generally in agreement with
your latter statements.

> For example, even apart from defining macros, which have obvious needs
> for exposure of the implementation for eval-when purposes, there are
> a number of macros used as interface functions, (e.g. loop, trace, etc),
> and there are a number of reasons to use macros (including
> compiler-macros) to effect optimizations.

Yes. All well reasoned uses of macros, though I would conseptually keep
compiler-macros and macros separate: the first is an implementation
detail, latter affects the interface.

> remains that most languages provide them, and for good reason.  The usage
> of each language feature must always be steeped in the wisdom of their best
> application, and precluding the use of a language feature unconditionally
> is at best naiive, and at worst repressive.

Yes, hence I didn't say "never use macros".

> The MOP is not standard, nor is it necessary to create classes at
> runtime.

True. But unless I'm missing something the only standard way to create a
class whose name won't be known before runtime is to call EVAL on a
DEFCLASS form.

I'd prefer investigating the state of MOP support in the used
implementation instead...

>> If you want to do X and the only interface to do it is via macros complain
>> to the implementor of that interface.

> I think if you follow this advice you will be frustrated.

Append " and figure out a workaround, even if ugly." to the advice,
then. 

I definitely believe the library/whatever implementor that the interface
is lacking is a crucial thing to do -- it costs you very little, but may
pay off hugely. Ditto for bug report. YMMV, of course.

> I do actually agree in general that the best interfaces that include
> macros will also provide a function-based interface, but it is not
> necessary, nor should it be a requirement.

Yes. Hard and fast requirements are seldom good. They tend to fail hard
and fast... 

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: Duane Rettig
Subject: Re: Dredging up patterns
Date: 
Message-ID: <4brkazzco.fsf@franz.com>
·········@random-state.net writes:

> Duane Rettig <·····@franz.com> wrote:
> 
> >> This is the classic example of where you should *not* use a macro. If you
> >> need the compile-time optimizations use inline declarations and
> >> compiler-macros -- and complain to your implementor if they don't work.
> >> 
> >> Now pick up the chalk and write 100 times on the blackboard: 
> >> 
> >>  "I shall not use macros as an optimization tool, nor shall I ever write a
> >>  macro that could be expressed equally well as a function or so help me
> >>  god."
> 
> > I snap your chalk in two, sir!  :-)
> 
> Hehee. ,-)
> 
> > As a general rule, I avoid making general rules.  This general rule
> > is especially pernicious, because it makes maxims out of rules that are
> > not stated or even implied in the Common Lisp spec or its tradition.
> 
> Ok. Somehow I've the feeling that you don't agree with the following
> statements either, however:
> 
>  "Using macros for optimization instead of inline declarations
>   and compiler macros is good practise."
> 
>  "Writing macros when the same interface can be expressed as a
>   function is good practice."
> 
> I certainly don't.

I don't consider them good or bad.  They're available for consideration.
If you want to consider down-sides for the first statement, consider first
that an implementation need not obey inline declarations, nor does it
need to expand compiler-macros.  So you may end up taking a chance on
getting the optimization you want.  Secondly, inline declarations are no
more space efficient than macros or compiler-macros, since they must store
the source of the definition in some form, in a similar manner to that of
macros and compiler-macros.

I would agree with you to disagree with the second, but I suspect we
might have to discuss what "can be expressed as a function" means for
various kinds of problems to solve.

> (As you note I was a bit more careful in qualifying these ones, and in
> spirit of historical revisionism apply similar qualification to my
> original guideline. Specifically I'm advocating against macros which could
> be equally well realized, with the same look and feel, as functions
> accompanied by compiler-macros or inline declarations.)

OK, but again I submit that Common Lisp does not follow this in its
loop and trace macros (note that we are really not far apart of this
issue; I implemented an ftrace function to implement trace, which comes
in handy mny times.  I only argued against the unequivocal nature of
your maxim, which you are now mitigating in an agreeable manner).

> Furthermore, I'm not sure whether I expressed my intention in a horribly
> muddled manner, or what, since I find myself generally in agreement with
> your latter statements.
> 
> > For example, even apart from defining macros, which have obvious needs
> > for exposure of the implementation for eval-when purposes, there are
> > a number of macros used as interface functions, (e.g. loop, trace, etc),
> > and there are a number of reasons to use macros (including
> > compiler-macros) to effect optimizations.
> 
> Yes. All well reasoned uses of macros, though I would conseptually keep
> compiler-macros and macros separate: the first is an implementation
> detail, latter affects the interface.
> 
> > remains that most languages provide them, and for good reason.  The usage
> > of each language feature must always be steeped in the wisdom of their best
> > application, and precluding the use of a language feature unconditionally
> > is at best naiive, and at worst repressive.
> 
> Yes, hence I didn't say "never use macros".

No, but you did say to never use macros under certain circumstances.

> > The MOP is not standard, nor is it necessary to create classes at
> > runtime.
> 
> True. But unless I'm missing something the only standard way to create a
> class whose name won't be known before runtime is to call EVAL on a
> DEFCLASS form.

Huh?

Put a defclass form into a file.  Create some instances of that class as
part of the compilation or loading of that file.  Works fine; no EVAL needed.

> I'd prefer investigating the state of MOP support in the used
> implementation instead...

Well, yes, you should always know the state of support of the MOP in
the implementation you are using, if you eventually want to use the
MOP.

> >> If you want to do X and the only interface to do it is via macros complain
> >> to the implementor of that interface.
> 
> > I think if you follow this advice you will be frustrated.
> 
> Append " and figure out a workaround, even if ugly." to the advice,
> then. 

But before that, I would append "and try to understand the motivation for
the library vendor's usage of a macro instead of a function.

Let me give you a counterexample, and why we may in fact disagree on
what is desirable to provide as a functional interface:

In Allegro CL, in versions up to 5.0, we provided a function call
ff:defforeign.  It is still available as a backward-compatibility
function, but has been deprecated.  When a user used defforeign,
he had to provide all of the eval-when semantics in his file, and there
was no way to leave out the majority of the foreign-definition
mechanism when loading the raw fasl file in - the entire defforeign
mechanism was required at all times.  Also, being a function made it
completely opaque, and you could never find out how various type
conversions were being interpreted.

Now, since version 5.0, we have had def-foreign-call, which is a macro.
a macroexpansion of the macro shows exactly what is going on, and
the data coversions, which have been normalized at macroexpand time,
are apparent.  Also, when the form is compiled into an interface file, and
that fasl file is loaded, it need not bring in the whole def-foreign-call
mechanism into the lisp, because it has _already_ been compiled away.
In fact, if the :call-direct option is used, and if functions in
different files which contain calls to these foreign functions are
successfully compiled into direct calls, then it is not even necessary
to load the original interface file in order to make the calls, since
they are compiled directly to the foreign definition _because_ the
def-foreign-call macro expanded itself away.

> I definitely believe the library/whatever implementor that the interface
> is lacking is a crucial thing to do -- it costs you very little, but may
> pay off hugely. Ditto for bug report. YMMV, of course.
> 
> > I do actually agree in general that the best interfaces that include
> > macros will also provide a function-based interface, but it is not
> > necessary, nor should it be a requirement.
> 
> Yes. Hard and fast requirements are seldom good. They tend to fail hard
> and fast... 

Agreed.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: ·········@random-state.net
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c933bu$bitn5$1@midnight.cs.hut.fi>
Duane Rettig <·····@franz.com> wrote:

> I don't consider them good or bad.  They're available for consideration.
> If you want to consider down-sides for the first statement, consider first
> that an implementation need not obey inline declarations, nor does it
> need to expand compiler-macros.  So you may end up taking a chance on
> getting the optimization you want.  

This is quite true, and quite annoying. I'm very happy/lucky that the
implementation I use respects inline declatations and expands
compiler-macros in a predictable fashion.

> Secondly, inline declarations are no
> more space efficient than macros or compiler-macros, since they must store
> the source of the definition in some form, in a similar manner to that of
> macros and compiler-macros.

True, but the equivalent macro is more error prone and cannot be
funcalled. Here inline functions pack more bang for the buck, imo.

> OK, but again I submit that Common Lisp does not follow this in its
> loop and trace macros (note that we are really not far apart of this
> issue; I implemented an ftrace function to implement trace, which comes
> in handy mny times.  I only argued against the unequivocal nature of
> your maxim, which you are now mitigating in an agreeable manner).

I see the point about TRACE, and agree that it could very well be a
function, but given that LOOP's raison d'entre is being a
sublanguage for iteration I fail to see how you would turn it into a
function.

>> True. But unless I'm missing something the only standard way to create a
>> class whose name won't be known before runtime is to call EVAL on a
>> DEFCLASS form.

> Huh?

> Put a defclass form into a file.  Create some instances of that class as
> part of the compilation or loading of that file.  Works fine; no EVAL needed.

Yes. No EVAL involved indeed. And unless you're interested in
the toplevelness of a generated form you can always replace (eval form) 
with (apply (compile nil `(lambda () ,@form))).

But as far as sharp tools and huge hammers go, I'd rate writing the code
to a file and compiling/loading that, just in order to define a class at
runtime as an even bigger hammer then EVAL.

So I'll fix my statement:

 "Unless I'm missing something the only standard way to create a
 class whose name won't be known before runtime is to generate the
 defclass from and smash that into the runtime environment with a huge
 hammer of your choise."

> But before that, I would append "and try to understand the motivation for
> the library vendor's usage of a macro instead of a function.

Oh, definitely. When you tell them "I want the underlying primitives to
play with." they may very well have good reasons not to. You may even be
pointed at the FAQ. ;-) 

> Let me give you a counterexample, and why we may in fact disagree on
> what is desirable to provide as a functional interface:

 --example elided--

I don't quite follow. To my ear this doesn't argue against a functional
interface except as a defining form. 

(Let me add to that that I don't think purely function based interfaces
are a goal in and on itself, though I think we already agreed on that.)

I'm not familiar with the macro-expansion of def-foreign-call, but if you
had/have a functional layer as well, I'd expect the functions that
def-foreign-call expands to (or some of them) to be part of that interface
-- but I definitely would not expect the defining form to be a function.

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyfu0y2jpkk.fsf@pcepsft001.cern.ch>
Duane Rettig <·····@franz.com> writes:

> ·········@random-state.net writes:
> 
> > Jacek Generowicz <················@cern.ch> wrote:
> > 
> > > whether the thing he is calling is a function or a macro. It being a
> > > macro could be an implementation detail:
> > 
> > > (defun average (&rest rest)
> > >   (/ (reduce #'+ rest)
> > >      (length rest)))
> > 
> > > (defmacro average (&body body)
> > >   `(/ (reduce #'+ ',body)
> > >       ,(length body)))
> > 
> > Nononono! It hurts, please stop!
> 
> Yesyesyes!  Don't stop; to remove the hurting, just fix the bug.

Would you be so kind as to show how you would implement this
particular optimization as a macro? I promise to study it carefully
... but I don't promise not to ask any stupid question about it.

Hopefully, seeing your code will help me reach a more considered
opinion about how wise it is to use macros for this purpose.

> > If you want to create classes at runtime, use the correct interface: MOP.
> 
> The MOP is not standard, nor is it necessary to create classes at
> runtime.

In the scenario I described (program parses C++ headers and creates
CLOS proxies), how would you proceed ?
From: Duane Rettig
Subject: Re: Dredging up patterns
Date: 
Message-ID: <4u0y1rimb.fsf@franz.com>
Jacek Generowicz <················@cern.ch> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > ·········@random-state.net writes:
> > 
> > > Jacek Generowicz <················@cern.ch> wrote:
> > > 
> > > > whether the thing he is calling is a function or a macro. It being a
> > > > macro could be an implementation detail:
> > > 
> > > > (defun average (&rest rest)
> > > >   (/ (reduce #'+ rest)
> > > >      (length rest)))
> > > 
> > > > (defmacro average (&body body)
> > > >   `(/ (reduce #'+ ',body)
> > > >       ,(length body)))
> > > 
> > > Nononono! It hurts, please stop!
> > 
> > Yesyesyes!  Don't stop; to remove the hurting, just fix the bug.
> 
> Would you be so kind as to show how you would implement this
> particular optimization as a macro? I promise to study it carefully
> ... but I don't promise not to ask any stupid question about it.

Try:

(defmacro average (&body body)
  `(/ (reduce #'+ (list ,@body))
      ,(length body)))

> Hopefully, seeing your code will help me reach a more considered
> opinion about how wise it is to use macros for this purpose.

Actually, I don't generally tend to use macros as optimizers;
I tend to use compiler-macros.  Again, I was not advocating for the
use of macros as optimization techniques, I was only advocating
against precluding them from being used as optimizers.

So what's the big difference between macros and compiler macros that
tends to make me favor the latter over the former?

The answer is:  namespaces.  Compiler-macros are slightly anomalous in
their treatment of namespaces in that they act in many ways to be in the
function namespace, but in one important way they act as if they are not
in the function namespace and that is that one can have a single name
naming both a function and a compiler-macro.  [Actually, this might be
in fact considered to be an attribute of the function namespace:  most
namespaces allow only one binding for a name at a time, but the function
namespace sometimes allows more than one binding at a time (for example,
you can't define a macro and a function at the same time with the same
name, but an implementation can define a macro and a special-operator
with the same name, and a user can define a function and a compiler-macro at
the same time.]  Anyway, since I can define a compiler-macro _and_ a
function at the same time, I get the benefits of macrology and inlining
as well as funcallability.

We have made use of the old "defsubst" technique of the LMs; in
Allegro CL 6.2 you can (require :defsubst) and have the defining macro
which defines both a function and a compiler-macro with the same
source.  Note that it is unexported in the excl package; it still
has some bugs and we haven't yet been satisfied with it enough to
export and document it, but it is useful for some applications:

CL-USER(1): (require :defsubst)
; Fast loading from bundle code/defsubst.fasl.
T
CL-USER(2): (excl::defsubst foo (a b c) (bar a b c))
FOO
CL-USER(3): (function-lambda-expression #'foo)
(LAMBDA (A B C) (BLOCK FOO (BAR A B C)))
NIL
FOO
CL-USER(4): (fdefinition '(compiler-macro foo))
#<Closure (FLET EXCL::EXPAND-DEFSUBST EXCL::DEFSUBST-EXPANDER) @
  #x717d2142>
CL-USER(5): 

It does not seem to handle &rest arguments correctly, so the
original example is among one of the buggy aspects of excl::defsubst.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyfpt8n5say.fsf@lxplus042.cern.ch>
Duane Rettig <·····@franz.com> writes:

> Jacek Generowicz <················@cern.ch> writes:
> 
> > Duane Rettig <·····@franz.com> writes:
> > 
> > > ·········@random-state.net writes:
> > > 
> > > > Jacek Generowicz <················@cern.ch> wrote:
> > > > 
> > > > > (defun average (&rest rest)
> > > > >   (/ (reduce #'+ rest)
> > > > >      (length rest)))
> > > > 
> > > > > (defmacro average (&body body)
> > > > >   `(/ (reduce #'+ ',body)
> > > > >       ,(length body)))

> Try:
> 
> (defmacro average (&body body)
>   `(/ (reduce #'+ (list ,@body))
>       ,(length body)))

Ironically enough though, this doesn't look any faster than the
original function it's supposed to optimize, as the macro-produced
code conses up a new list of arguments each time. (A quick and dirty
test on the CL implementation I happened to have open (SBCL) suggests
that it is indeed a bit slower.) Still, this is orthogonal to the issue.

> since I can define a compiler-macro _and_ a function at the same
> time, I get the benefits of macrology and inlining as well as
> funcallability.

Indeed. Though I have this nagging fear in the back of my mind about compiler
macros: the possibility that the two implementations are subtly
different leading to difficult to find bugs. Do people get stung by
this?
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87fz9epmub.fsf@nyct.net>
Jacek Generowicz <················@cern.ch> writes:

> Ironically enough though, this doesn't look any faster than the
> original function it's supposed to optimize, as the macro-produced
> code conses up a new list of arguments each time. (A quick and dirty
> test on the CL implementation I happened to have open (SBCL) suggests
> that it is indeed a bit slower.) Still, this is orthogonal to the issue.

Indeed, because what you REALLY want to use is a compiler macro,
although an inline function is far easier. If some users'
implementations don't inline functions or don't inline them well, that's
their choice to have that tradeoff. Why should you jump though hoops
just because some compilers aren't good at optimizing some things? Does
that mean you won't use numbers greater than 2^23 on any implementation
even though clisp is really fast at doing math with those numbers?

> Indeed. Though I have this nagging fear in the back of my mind about compiler
> macros: the possibility that the two implementations are subtly
> different leading to difficult to find bugs. Do people get stung by
> this?

You got stung by the equivalent: your implementation of average was (a
bit more than subtly) different from the one you intended. If the
optimization is really that hard to code up, then you're dealing with
serious programming, and serious anything isn't light work. Writing
optimizers of any kind for various types of operators is, in general,
quite arduous in terms of both sheer workload as well as time you need
to spend thinking about the performance semantics you can achieve based
on the information you have available at compile time.

Oh, and your whole concept of wanting to use a macro instead of a
compiler-macro for AVERAGE as an optimization is a non-sequitur. If you
use it as you want to (with APPLY doing an EVAL) you've just blown any
chance you have of getting your code to be fast.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyfekoyigv2.fsf@pcepsft001.cern.ch>
Rahul Jain <·····@nyct.net> writes:

> > Indeed. Though I have this nagging fear in the back of my mind
> > about compiler macros: the possibility that the two
> > implementations are subtly different leading to difficult to find
> > bugs. Do people get stung by this?
> 
> You got stung by the equivalent: your implementation of average was (a
> bit more than subtly) different from the one you intended.

Yes, but having only one implementation of the functionality, which
gets used in all possible contexts would soon make the problems show
up. My question is about having different implementations of the same
functionality being used in different contexts, and how likely this is
to make some sorts of bugs harder to spot.

> If the optimization is really that hard to code up,

The original macro was never meant to be a demonstration of how to do
it correctly ... it was meant to be a token illustration of _why_ one
_might_ want to use a macro. I'll be the first to admit that not much
thought went into the actual details of its implementation.

> Oh, and your whole concept of wanting to use a macro instead of a
> compiler-macro for AVERAGE as an optimization is a non-sequitur. If you
> use it as you want to (with APPLY doing an EVAL) you've just blown any
> chance you have of getting your code to be fast.

Yes ... but does that somehow invalidate the desire to make it be fast
in those situations where I am not using APPLY or EVAL ?
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87k6ypcuoe.fsf@nyct.net>
Jacek Generowicz <················@cern.ch> writes:

> Rahul Jain <·····@nyct.net> writes:
>
>> You got stung by the equivalent: your implementation of average was (a
>> bit more than subtly) different from the one you intended.
>
> Yes, but having only one implementation of the functionality, which
> gets used in all possible contexts would soon make the problems show
> up.

Exactly. That's what the INLINE declaration exists.

>> If the optimization is really that hard to code up,
>
> The original macro was never meant to be a demonstration of how to do
> it correctly ... it was meant to be a token illustration of _why_ one
> _might_ want to use a macro. I'll be the first to admit that not much
> thought went into the actual details of its implementation.

One might want a macro in that case if one were using a deficient
implementation. Why should optimization of such minor amounts be a
concern when you're satisfied with a compiler that doesn't do the basic
ones?

>> Oh, and your whole concept of wanting to use a macro instead of a
>> compiler-macro for AVERAGE as an optimization is a non-sequitur. If you
>> use it as you want to (with APPLY doing an EVAL) you've just blown any
>> chance you have of getting your code to be fast.
>
> Yes ... but does that somehow invalidate the desire to make it be fast
> in those situations where I am not using APPLY or EVAL ?

If you want that, declare it inline or write a compiler-macro if there
is some more intelligent optimization that can be done by grovelling
through the code that computes the arguments..

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Kalle Olavi Niemitalo
Subject: What is a "body"? (was: Dredging up patterns)
Date: 
Message-ID: <87d64cie45.fsf_-_@Astalo.kon.iki.fi>
Duane Rettig <·····@franz.com> writes:

> (defmacro average (&body body)
>   `(/ (reduce #'+ (list ,@body))
>       ,(length body)))

Is that an appropriate use of &BODY, as opposed to &REST?

I was under the impression that in a "body", only the values of
the last form would be used, which is not the case here.  The AND
macro is similar in this respect, and its specification does not
mention a body.  On the other hand, TAGBODY is specified to take
a body, yet it ignores the values of _all_ forms.  What does the
term really mean?
From: Kenny Tilton
Subject: Re: What is a "body"?
Date: 
Message-ID: <evMwc.108865$Nn4.23818272@twister.nyc.rr.com>
Kalle Olavi Niemitalo wrote:

> Duane Rettig <·····@franz.com> writes:
> 
> 
>>(defmacro average (&body body)
>>  `(/ (reduce #'+ (list ,@body))
>>      ,(length body)))
> 
> 
> Is that an appropriate use of &BODY, as opposed to &REST?
> 
> I was under the impression that in a "body", only the values of
> the last form would be used, which is not the case here.  The AND
> macro is similar in this respect, and its specification does not
> mention a body.  On the other hand, TAGBODY is specified to take
> a body, yet it ignores the values of _all_ forms.  What does the
> term really mean?

 From CLHS 3.4.4 Macro Lambda Lists:

"&body is identical in function to &rest, but it can be used to inform 
certain output-formatting and editing functions that the remainder of 
the form is treated as a body, and should be indented accordingly. "

You do not want the list of addends formatted as if they were a body of 
code, so &rest would be more appropriate.

kenny

-- 
Home? http://tilton-technology.com
Cells? http://www.common-lisp.net/project/cells/
Cello? http://www.common-lisp.net/project/cello/
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Your Project Here! http://alu.cliki.net/Industry%20Application
From: Kalle Olavi Niemitalo
Subject: Re: What is a "body"?
Date: 
Message-ID: <87oenuy0mr.fsf@Astalo.kon.iki.fi>
Kenny Tilton <·······@nyc.rr.com> writes:

>  From CLHS 3.4.4 Macro Lambda Lists:
>
> "&body is identical in function to &rest, but it can be used to inform
> certain output-formatting and editing functions that the remainder of
> the form is treated as a body, and should be indented accordingly. "

I've read that, but it doesn't say what a body is or how one
should be indented.  A TAGBODY form has a body, and I believe it
is customary to indent the statements more than the tags.  Yet,
I don't think that can be a general property of all bodies.

> You do not want the list of addends formatted as if they were a body
> of code, so &rest would be more appropriate.

I might want that, if I knew for sure what it means.
From: Ari Johnson
Subject: Re: What is a "body"?
Date: 
Message-ID: <lHexc.610$E03.457@fed1read01>
Kalle Olavi Niemitalo wrote:
> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>> From CLHS 3.4.4 Macro Lambda Lists:
>>
>>"&body is identical in function to &rest, but it can be used to inform
>>certain output-formatting and editing functions that the remainder of
>>the form is treated as a body, and should be indented accordingly. "
> 
> 
> I've read that, but it doesn't say what a body is or how one
> should be indented.  A TAGBODY form has a body, and I believe it
> is customary to indent the statements more than the tags.  Yet,
> I don't think that can be a general property of all bodies.
> 
> 
>>You do not want the list of addends formatted as if they were a body
>>of code, so &rest would be more appropriate.
> 
> 
> I might want that, if I knew for sure what it means.

The point is that, when it comes to compiling your code, &rest and &body 
are synonymous.  The only time a &body argument is treated differently 
than a &rest argument is when the code calling the function or macro in 
question is formatted for human readability.  If tags in a tagbody are 
indented differently, that's because the program doing the formatting is 
smart enough to see 'tagbody' and act accordingly.

Also, tagbody isn't just a user-defined macro, but indeed is a special 
operator, and anything that formats code should at least intelligently 
format all special forms.

Now, a /really/ smart code formatter would format things like the 
following (and anything that is more complex but of similar form) as 
they would a tagbody:

(defmacro foo (&body body)
   `(tagbody ,@body))
(foo a (go a))

At least that's my take.
From: Barry Margolin
Subject: Re: What is a "body"?
Date: 
Message-ID: <barmar-413E47.12224008062004@comcast.dca.giganews.com>
In article <··············@Astalo.kon.iki.fi>,
 Kalle Olavi Niemitalo <···@iki.fi> wrote:

> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> >  From CLHS 3.4.4 Macro Lambda Lists:
> >
> > "&body is identical in function to &rest, but it can be used to inform
> > certain output-formatting and editing functions that the remainder of
> > the form is treated as a body, and should be indented accordingly. "
> 
> I've read that, but it doesn't say what a body is or how one
> should be indented.  A TAGBODY form has a body, and I believe it
> is customary to indent the statements more than the tags.  Yet,
> I don't think that can be a general property of all bodies.

In general, a body is an implicit progn, like the body of a function 
definition.  TAGBODY is a special case because it allows tags to be 
interspersed with the expressions in its body, and it's reasonable to 
treat them specially in indentation because they're treated specially in 
the semantics.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: ·········@random-state.net
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c94acu$bkbp9$1@midnight.cs.hut.fi>
Jacek Generowicz <················@cern.ch> wrote:

> In the scenario I described (program parses C++ headers and creates
> CLOS proxies), how would you proceed ?

If you're essentially working in batches, that is "parse bunch of stuff,
create proxies, use them a lot", then I think any huge hammer approach is
quite valid, Duane's (load (compile-file ...)) being probably the nicest.

If you're constantly creating new proxies based on information that keeps
trickling in, then I'd suggest moppery.

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyfy8nejq8c.fsf@pcepsft001.cern.ch>
·········@random-state.net writes:

> Jacek Generowicz <················@cern.ch> wrote:
> 
> > whether the thing he is calling is a function or a macro. It being a
> > macro could be an implementation detail:
> 
> > (defun average (&rest rest)
> >   (/ (reduce #'+ rest)
> >      (length rest)))
> 
> > (defmacro average (&body body)
> >   `(/ (reduce #'+ ',body)
> >       ,(length body)))
> 
> Nononono! It hurts, please stop!

Heh.

I was tempted, at that point in the original post, to mention that
this is probably a good example demonstrating why you shouldn't use
macros for optimization :-)

> This is the classic example of where you should *not* use a macro. If you
> need the compile-time optimizations use inline declarations and
> compiler-macros -- and complain to your implementor if they don't work.
> 
> Now pick up the chalk and write 100 times on the blackboard: 
> 
>  "I shall not use macros as an optimization tool, nor shall I ever write a
>  macro that could be expressed equally well as a function or so help me
>  god."

I know this, but going through the excercise will probably be good for
me anyway. Will a whiteboard and an Edding 360 blue marker pen do
instead? :-)

> If you want to create classes at runtime, use the correct interface: MOP.

You are absolutely right. Shifting topic slightly now ... how would
you create classes at runtime in CL _portably_ ?
From: David Steuber
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87aczu9mdf.fsf@david-steuber.com>
Jacek Generowicz <················@cern.ch> writes:

> I know this, but going through the excercise will probably be good for
> me anyway. Will a whiteboard and an Edding 360 blue marker pen do
> instead? :-)

Huffing white board markers is bad, m'kay?

> > If you want to create classes at runtime, use the correct interface: MOP.
> 
> You are absolutely right. Shifting topic slightly now ... how would
> you create classes at runtime in CL _portably_ ?

That's easy.  Write a portable MOP library and use it.

-- 
A real world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyflljejg1u.fsf@pcepsft001.cern.ch>
David Steuber <·····@david-steuber.com> writes:

> Jacek Generowicz <················@cern.ch> writes:
>
> > You are absolutely right. Shifting topic slightly now ... how would
> > you create classes at runtime in CL _portably_ ?
> 
> That's easy.  Write a portable MOP library and use it.

Doh! Now why didn't I think of this simple, elegant solution myself?

:-)
From: Timothy Moore
Subject: Re: Dredging up patterns
Date: 
Message-ID: <wdr8yfeuh8v.fsf@trousse.labri.fr>
Jacek Generowicz <················@cern.ch> writes:

> David Steuber <·····@david-steuber.com> writes:
> 
> > Jacek Generowicz <················@cern.ch> writes:
> >
> > > You are absolutely right. Shifting topic slightly now ... how would
> > > you create classes at runtime in CL _portably_ ?
> > 
> > That's easy.  Write a portable MOP library and use it.
> 
> Doh! Now why didn't I think of this simple, elegant solution myself?
> 
> :-)

Don't know, it seems quite reasonable to me. McCLIM has been ported to
five Common Lisp implementations -- one of which, OpenMCL, has quite
different MOP support in its two major versions -- using this
approach. McCLIM is a reasonably sophisticated user of the MOP.

If you're want to do MOP stuff and are determined to have your code
work in implementations that don't have a MOP at all, that's obviously
harder.

Tim
From: Dave Fayram
Subject: Re: Dredging up patterns
Date: 
Message-ID: <38ff3d6c.0405270753.36d440be@posting.google.com>
Jacek Generowicz <················@cern.ch> wrote in message news:
> You are absolutely right. Shifting topic slightly now ... how would
> you create classes at runtime in CL _portably_ ?

Well, MOP still isn't a bad bet. :) SBCL, CMUCL, and OpenMCL all give
you most of the MOP (although there are some differences here and
there, I don't think they'll bite you). I haven't played much with the
commercial lisps, to be honest. Cursory glance at Allegro suggests it
doesn't do it, but then I know Allegro about as well as I know
LispWorks, which is to say barely at all. If I'm wrong on that,
someone will surely correct me within minutes of this post.

If you want to get really intense about it, you can eval specially
constructed defclass forms, I guess. This will be the maximum-expense
option, but at least the code will be pretty simple and it's
guaranteed to work right.

At least with MOP you have a programatic option. With, say, Ruby,
you'd have to eval a string form after running some regular
expressions on it. :)

Reading what you said about your project-making proxy classes for
other objects-I think MOP might be just what you need even without
this problem. If you're making special classes where a slot might not
really be a slot, and special actions need to be taken for
instantiations of classes, then writing it via MOP as an extension to
CLOS isn't a bad idea.

- dlf
From: Arthur Lemmens
Subject: Re: Dredging up patterns
Date: 
Message-ID: <opr8o8lae5k6vmsw@news.xs4all.nl>
Dave Fayram <·········@lensmen.net> wrote:

> Well, MOP still isn't a bad bet. :) SBCL, CMUCL, and OpenMCL all give
> you most of the MOP (although there are some differences here and
> there, I don't think they'll bite you). I haven't played much with the
> commercial lisps, to be honest. Cursory glance at Allegro suggests it
> doesn't do it

Both Allegro and Lispworks implement almost the whole MOP.
There's an interesting article by Tim Bradshaw which compares Lisp
implementations w.r.t. the MOP features they implement, by the way.

Arthur Lemmens
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyf4qq1j7qg.fsf@pcepsft001.cern.ch>
Arthur Lemmens <········@xs4all.nl> writes:

> There's an interesting article by Tim Bradshaw which compares Lisp
> implementations w.r.t. the MOP features they implement, by the way.

You mean this, I guess:

http://www.franz.com/services/conferences_seminars/jlugm00/conference/Talk02_deLacaze1.pdf

Is that the canonical URL ?
From: Arthur Lemmens
Subject: Re: Dredging up patterns
Date: 
Message-ID: <opr8pbeptak6vmsw@news.xs4all.nl>
Jacek Generowicz <················@cern.ch> wrote:

> Arthur Lemmens <········@xs4all.nl> writes:
>
>> There's an interesting article by Tim Bradshaw which compares Lisp
>> implementations w.r.t. the MOP features they implement, by the way.
>
> You mean this, I guess:
>
> http://www.franz.com/services/conferences_seminars/jlugm00/conference/Talk02_deLacaze1.pdf

Yes.

> Is that the canonical URL ?

I don't know. I suppose you should ask Tim Bradshaw.
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyf8yfdj7wh.fsf@pcepsft001.cern.ch>
·········@lensmen.net (Dave Fayram) writes:

> Reading what you said about your project-making proxy classes for
> other objects-I think MOP might be just what you need even without
> this problem. If you're making special classes where a slot might not
> really be a slot, and special actions need to be taken for
> instantiations of classes, then writing it via MOP as an extension to
> CLOS isn't a bad idea.

Sure. The C++ object system maps pretty poorly to CLOS, so you'd
probably want to use the MOP to make C++-like classes anyway, if you
were to do this in CL. (I'm actually doing it in Python, where the
object system looks much more like the C++ one than does CLOS ... and
there I can do everything programatically by creating and
instantiating metaclasses.)
From: Jeff Dalton
Subject: Re: Dredging up patterns
Date: 
Message-ID: <fx4oeo9lvrw.fsf@todday.inf.ed.ac.uk>
·········@random-state.net writes:

> Jacek Generowicz <················@cern.ch> wrote:
> 
> > whether the thing he is calling is a function or a macro. It being a
> > macro could be an implementation detail:
> 
> > (defun average (&rest rest)
> >   (/ (reduce #'+ rest)
> >      (length rest)))
> 
> > (defmacro average (&body body)
> >   `(/ (reduce #'+ ',body)
> >       ,(length body)))
> 
> Nononono! It hurts, please stop!
> 
> This is the classic example of where you should *not* use a macro. If you
> need the compile-time optimizations use inline declarations and
> compiler-macros -- and complain to your implementor if they don't work.

There used to be a macro (I think it goes back to MacLisp)
called defsubst that defined a function and a compiler-macro
that did the same thing.  You'd give one definition that
looked like a function definition, except saying defsubst
instead of defun, and it would write the macro for you,
using a once-only macro to ensure args didn't get evaluated
more than once in the macro version.

Re the earlier point 

  Pattern: Don't use macros.
  Problem: Ever try to mapcar over a macro in Common Lisp?
  Solution: Certain jaded outlook.

and "smell" -- talk of "smell" is a good way to avoid giving
an argument or an actual reason.  In a refactoring context,
it can make good sense, because the constructs that supposedly
smell are ones that are often good candidates for refactoring.
Macros that could have been defined as functions is a
plausible example.  But "smell" isn't a good general argument
against using macros (or against anything else).

-- jd
From: Christopher C. Stacy
Subject: Re: Dredging up patterns
Date: 
Message-ID: <u8yfdrb0u.fsf@news.dtpq.com>
>>>>> On 27 May 2004 16:44:35 +0100, Jeff Dalton ("Jeff") writes:

 Jeff> ·········@random-state.net writes:
 >> Jacek Generowicz <················@cern.ch> wrote:
 >> 
 >> > whether the thing he is calling is a function or a macro. It being a
 >> > macro could be an implementation detail:
 >> 
 >> > (defun average (&rest rest)
 >> >   (/ (reduce #'+ rest)
 >> >      (length rest)))
 >> 
 >> > (defmacro average (&body body)
 >> >   `(/ (reduce #'+ ',body)
 >> >       ,(length body)))
 >> 
 >> Nononono! It hurts, please stop!
 >> 
 >> This is the classic example of where you should *not* use a macro. If you
 >> need the compile-time optimizations use inline declarations and
 >> compiler-macros -- and complain to your implementor if they don't work.

 Jeff> There used to be a macro (I think it goes back to MacLisp)
 Jeff> called defsubst that defined a function and a compiler-macro
 Jeff> that did the same thing.  You'd give one definition that
 Jeff> looked like a function definition, except saying defsubst
 Jeff> instead of defun, and it would write the macro for you,
 Jeff> using a once-only macro to ensure args didn't get evaluated
 Jeff> more than once in the macro version.

I don't think MACLISP had it; it was a Lisp Machine thing.
This was functionally superseded in CL by the INLINE declaration.
From: Jeff Dalton
Subject: Re: Dredging up patterns
Date: 
Message-ID: <fx4k6yxl4lj.fsf@todday.inf.ed.ac.uk>
······@news.dtpq.com (Christopher C. Stacy) writes:

> >>>>> On 27 May 2004 16:44:35 +0100, Jeff Dalton ("Jeff") writes:

>  Jeff> There used to be a macro (I think it goes back to MacLisp)
>  Jeff> called defsubst that defined a function and a compiler-macro
>  Jeff> that did the same thing.  You'd give one definition that
>  Jeff> looked like a function definition, except saying defsubst
>  Jeff> instead of defun, and it would write the macro for you,
>  Jeff> using a once-only macro to ensure args didn't get evaluated
>  Jeff> more than once in the macro version.

> I don't think MACLISP had it; it was a Lisp Machine thing.
> This was functionally superseded in CL by the INLINE declaration.

You're probably right that it started on the LM, but I'm
pretty sure it was available for MacLisp.  I also had a
version that I used in Franz Lisp.

I am not convinced that the functionality was superseded.
CL has compiler macros, it is a natural use of compiler
macros, and in some CL implementations (at least) is will
work when declaring something inline will not.

The intention probably was to have inline supersede
defsubst and the like, but I don't think it's turned out
that way.

-- jd
From: Mario S. Mommer
Subject: Re: Dredging up patterns
Date: 
Message-ID: <fzoeo9dg5z.fsf@germany.igpm.rwth-aachen.de>
·········@random-state.net writes:
> If you want to create classes at runtime, use the correct interface: MOP.

I find this odd. If all you want to do is to execute

  (defclas foo ...)

at runtime, what is wrong with eval/compile? It is a simple, portable,
and straight-forward solution which will just work. And why is writing
said form first to a file and then calling compile-file+load less of a
big hammer, or "cleaner", than simply calling eval/compile directly?
From: Mario S. Mommer
Subject: Re: Dredging up patterns
Date: 
Message-ID: <fzk6yxdfza.fsf@germany.igpm.rwth-aachen.de>
Mario S. Mommer <········@yahoo.com> writes:
> And why is writing said form first to a file and then calling
> compile-file+load less of a big hammer, or "cleaner", than simply
> calling eval/compile directly?

Ugh, I see you already answered that in another post. Sorry...
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87oeo2pnpj.fsf@nyct.net>
Jacek Generowicz <················@cern.ch> writes:

> This shouldn't be such an alien concept: when working interactively,
> at the REPL, we keep calling macros at runtime. In Lisp, there is no
> strict ordering and separation of macro expansion time -> compile time
> -> run time, such as one finds in less flexible languages.

Ugh. I wish Kent were here to give his usual explanation of times in
Lisp. Time always exists, Lisp just doesn't have the constraints other
languages have on what you can do at what times.

> For example what if I want to create a new class at runtime based on
> some information I calculate[*]? I would like to be able to "call"
> defclass at runtime, passing it some data which was not available
> until runtime. As a user of defclass, I do not care that is a macro,
> to me it is "that which creates classes" and "that which creates
> classes" happens to be what I need right now, at runtime.

No. You do care that it is a macro because ENSURE-CLASS is a function. 
DEFCLASS is a convenient syntactic way of expressing an ENSURE-CLASS,
but it has a very different interface.

>> Consider (mapcar 'macro (list 1 2 3)).  You are asking that a
>> compile-time computation be applied to the run-time list value (1 2 3).
>> What then, is the difference from a function?
>
> That is a question you would have to ask the implementor, not the
> user.

That makes no sense. If the user won't understand what he means by his
code, what use is it?

>> Or perhaps that it be applied to the compile-time source code list value
>> (list 1 2 3).  Yet macro functions are supposed to return valid lisp
>> forms; what could this macro return that would be valid when fed to the
>> compiler?
>
> As a user, I do not care. But I would hope that the final result is
> equivalent to
>
> (list (macro 1) (macro 2) (macro 3))

Then you're insane. Why would mapping a macro over the elements of a
list somehow treat some elements of that list differently from others. 
How would it know?

Or maybe the question is: why are you evaluating the arguments to a
macro? If you believe that you aren't calling a macro, then why are you
trying to abstract syntactically when all syntactic information is
compiled away and all that's left that you can be sure about are the
semantics your syntax described?

> Macros are indistiguishable from functions at the call site, the
> question is "how far can we push the luxury of ignorance about their
> true nature?"

They're only indistinguishable if the caller has no concept of what the
call is supposed to accomplish. You might as well say that lists are
indistingushable from arrays at the site that accesses an element from
it. Would you use CDR to traverse an array? Would you use DOTIMES + AREF
to traverse a list?

> [*] I'm working on a project which aims to reflect C++ classes in
>     another language (unfortunately not Lisp) by inspecting header
>     files, and creating proxy classes in the other language. So
>     creating classes at runtime IS a real-world example.

Indeed it is. ENSURE-CLASS creates classes at its run time. DEFCLASS's
run time is when the form is macroexpanded either just before
interpretation or during compilation.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyfaczmiews.fsf@pcepsft001.cern.ch>
Rahul Jain <·····@nyct.net> writes:

> Jacek Generowicz <················@cern.ch> writes:
> 
> >> Consider (mapcar 'macro (list 1 2 3)).  You are asking that a
> >> compile-time computation be applied to the run-time list value (1 2 3).
> >> What then, is the difference from a function?

> >> Or perhaps that it be applied to the compile-time source code list value
> >> (list 1 2 3).  Yet macro functions are supposed to return valid lisp
> >> forms; what could this macro return that would be valid when fed to the
> >> compiler?
> >
> > As a user, I do not care. But I would hope that the final result is
> > equivalent to
> >
> > (list (macro 1) (macro 2) (macro 3))
> 
> Then you're insane.

Thank you for your expert and topical opinion. It's really helping me
to understand the technical issues under consideration.

> Why would mapping a macro over the elements of a list somehow treat
> some elements of that list differently from others. How would it
> know?

My point (and question elsewhere in the thread) is about to what
extent the user is supposed to know whether the symbol in the car
position of a form refers to a macro or function. My queries are about
to what extent one can afford the luxury of ignorance about its macro
vs function nature ... bearing that in mind, I would hope that

  (mapcar 'foo (list 1 2 3))

results in

  (list (foo 1) (foo 2) (foo 3))

and if you allow me to wallow in said luxury of ignorance, you might
understand the source of my insanity.

Your answer to the question about to what extent one can afford the
luxury of ignorace, seems to be "not at all", though your delivery
style seems to emphasize an orthogonal message.
From: ·········@random-state.net
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c9kaam$c9r6m$1@midnight.cs.hut.fi>
Jacek Generowicz <················@cern.ch> wrote:

> My point (and question elsewhere in the thread) is about to what
> extent the user is supposed to know whether the symbol in the car
> position of a form refers to a macro or function. My queries are about

To no degree at all. 

Like Rahul said, whether the operator is function or a macro is part of
its interface. Just like you need to know other bits about the interface,
you need to know which it is.

If you find this a great burden, I'm reasonably sure that it would be
no great feat of elisp-fu to make emacs & slime colour macro-names in
operator position differently from function names.

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: ·········@random-state.net
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c9kf57$cblut$1@midnight.cs.hut.fi>
·········@random-state.net wrote:
> Jacek Generowicz <················@cern.ch> wrote:

>> My point (and question elsewhere in the thread) is about to what
>> extent the user is supposed to know whether the symbol in the car
>> position of a form refers to a macro or function. My queries are about

> To no degree at all. 

Um. I ment just the opposite, of course. 

Note to self: do not post before finishing the first cup of coffee.

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyfwu2qge1i.fsf@pcepsft001.cern.ch>
·········@random-state.net writes:

> Jacek Generowicz <················@cern.ch> wrote:
> 
> > My point (and question elsewhere in the thread) is about to what
> > extent the user is supposed to know whether the symbol in the car
> > position of a form refers to a macro or function. My queries are about

> Like Rahul said, whether the operator is function or a macro is part of
> its interface. Just like you need to know other bits about the interface,
> you need to know which it is.
> 
> If you find this a great burden,

No, not at all. I merely wanted to check whether this is universally
accepted by the good and the wise.
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87fz9dcubr.fsf@nyct.net>
Jacek Generowicz <················@cern.ch> writes:

>> Like Rahul said, whether the operator is function or a macro is part of
>> its interface. Just like you need to know other bits about the interface,
>> you need to know which it is.
>> 
>> If you find this a great burden,
>
> No, not at all. I merely wanted to check whether this is universally
> accepted by the good and the wise.

You're wondering whether it's good and wise to know that a hammer should
be held by the narrow end whereas a saw should be held by the wide end? 
Do you get into a car and randomly press buttons and turn knobs and
wheels, hoping it'll go in the right direction just because you know
that a car is useful for getting someone from one place to another and
you'll be damned if you're going to spend the time knowing that moves on
the ground and not over the water?

C'mon, give your human genes more credit than that. Of _course_ it's
good and wise to know what kind of thing you're using before you use it
and what parts of it do what.

You put the key in the keyhole just like you put the bindings list in
the second position of a LET form.

Which brings me to another thought. How would you expect
(apply 'let (((a 1)) (print a)))
to work?

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Joe Marshall
Subject: Re: Dredging up patterns
Date: 
Message-ID: <3c5djrj2.fsf@comcast.net>
Jacek Generowicz <················@cern.ch> writes:

> ·········@random-state.net writes:
>
>> Jacek Generowicz <················@cern.ch> wrote:
>> 
>> > My point (and question elsewhere in the thread) is about to what
>> > extent the user is supposed to know whether the symbol in the car
>> > position of a form refers to a macro or function. My queries are about
>
>> Like Rahul said, whether the operator is function or a macro is part of
>> its interface. Just like you need to know other bits about the interface,
>> you need to know which it is.
>> 
>> If you find this a great burden,
>
> No, not at all. I merely wanted to check whether this is universally
> accepted by the good and the wise.

It isn't *universally* accepted, but it seems to be a good compromise
between incredible complexity and low performance versus slightly more
intellectual burden and efficient compilation.


-- 
~jrm
From: Joe Marshall
Subject: Re: Dredging up patterns
Date: 
Message-ID: <brk2kq7f.fsf@comcast.net>
Jacek Generowicz <················@cern.ch> writes:

> Yes, but there is no way of distinguishing a macro from a function by
> analysys of the call point. 

This is true to some extent.  For some macros it is easy to deduce
that they are not functions because normal evaluation rules would make
no sense.  Others are easily distinguished by naming conventions.
However it is possible to create a macro that appears prima facie a
function.

> The user does not (necessarily) know whether the thing he is calling
> is a function or a macro. It being a macro could be an
> implementation detail:
>
> (defun average (&rest rest)
>   (/ (reduce #'+ rest)
>      (length rest)))
>
> (defmacro average (&body body)
>   `(/ (reduce #'+ ',body)
>       ,(length body)))

Macros are fundamentally different from functions.  Macros operate on
the syntactic level, not the semantic level.  Users (in general) need
to know whether they are syntactically expressing a function call or
whether they are expressing something altogether different.

In Lisp, you can deliberately blur the syntactic distinction between
macro and function.  This can be used to good effect if it reduces the
intellectual burden on the user --- he doesn't need to think too hard
about whether he is using a macro or function, he just uses it.
Common Lisp's CHECK-TYPE macro is a terrific example of this.  It
doesn't really `seem' to be a macro.

But one reason CHECK-TYPE works so well is that it's focus on a single
variable and type does not obviously lend itself to generalization.
It doesn't seem like the kind of `function' you'd want to MAPCAR.

> This shouldn't be such an alien concept: when working interactively,
> at the REPL, we keep calling macros at runtime. In Lisp, there is no
> strict ordering and separation of macro expansion time -> compile time
> -> run time, such as one finds in less flexible languages.

Yes, there is, but unlike less flexible languages, you do not need to
blow away the runtime environment to relink in new code.  But macro
expansion *always* (and logically *must*) preceed the execution of the
macro form.  And obviously macro definition must preceed the
expansion. 

> For example what if I want to create a new class at runtime based on
> some information I calculate[*]?  I would like to be able to "call"
> defclass at runtime, passing it some data which was not available
> until runtime.  As a user of defclass, I do not care that is a macro,
> to me it is "that which creates classes" and "that which creates
> classes" happens to be what I need right now, at runtime.

It is useful to distinguish between `declaration' and execution.
Although Lisp allows you to ignore this on the small scale (at the
REPL) it should not be ignored on the large scale (when compiling a
system).  Declaring forms such as DEFCLASS, DEFUN, DEFVAR,
etc. instruct the compiler to arrange for the effect to be done when
the file is loaded (or immediately after).  DEFUN doesn't create a
function, it declares that after the file is loaded the named function
will exist.  It is a subtle point because DEFUN at the REPL certainly
*appears* to create a named function.

DEFCLASS in a lisp source file *declares* a class.  The compiler
arranges for the class to exist when the file is loaded.  But if you
want to create a class `on the fly', DEFCLASS is not what you want.
Unfortunately, there is no standard runtime function for creating new
classes, so you need to do one of two things:  find the non-standard
function that the system uses to instantiate classes, or fake up a
DEFCLASS form and EVAL it.  Fortunately, the MOP defines ENSURE-CLASS
as the API to instantiate a class and many lisp systems implement
this.

>> Consider (mapcar 'macro (list 1 2 3)).  You are asking that a
>> compile-time computation be applied to the run-time list value (1 2 3).
>> What then, is the difference from a function?
>
> That is a question you would have to ask the implementor, not the
> user.
>
>> Or perhaps that it be applied to the compile-time source code list value
>> (list 1 2 3).  Yet macro functions are supposed to return valid lisp
>> forms; what could this macro return that would be valid when fed to the
>> compiler?
>
> As a user, I do not care. But I would hope that the final result is
> equivalent to
>
> (list (macro 1) (macro 2) (macro 3))

Under what conditions would you hope this?

MACLISP had `fexprs' which were functions that did not evaluate their
arguments, but even these would not help in this case.  Consider this:

(defun my-macro (&body body) `(quote ,(cadr body)))

(defun func-or-mac ()
  (if (zerop (random 2)) #'identity #'my-macro))

;; A really strange implementation of list.
(defun foo (&rest args) (mapcar #'identity args))

(let ((a 1)
      (b 2)
      (c 3))
  (mapcar (func-or-mac) (foo (+ a 2) (+ b 4) (+ c 6))))

If you map the function, you get the list (3 6 9), but 

(list (macro (+ a 2)) (macro (+ b 4)) (macro (+ c 6)))

would evaluate to the list (a b c).

Now how would the compiler arrange for this?  The source code for the
macro to operate on could come from literally anywhere!  Must all code
therefore keep around the original fragments of source code just in
case someone tries to pass macro around?

> Macros are indistiguishable from functions at the call site, the
> question is "how far can we push the luxury of ignorance about their
> true nature?"

You cannot push them very far at all.  This is a good reason to *not*
make macros indistinguishable from function calls.

However, a COMPILER-MACRO is something that might interest you.  A
COMPILER-MACRO is a mechanism by which you can inform the compiler how
to optimize certain patterns of function usage.  You supply a function
definition as normal (using DEFUN), but when the compiler notices a
form that indicates a call to function, it invokes the COMPILER-MACRO
for a possible rewrite.


-- 
~jrm
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyf4qpt60jh.fsf@lxplus034.cern.ch>
Joe Marshall <·············@comcast.net> writes:

> Jacek Generowicz <················@cern.ch> writes:
> 
> In Lisp, you can deliberately blur the syntactic distinction between
> macro and function.  This can be used to good effect if it reduces the
> intellectual burden on the user --- he doesn't need to think too hard
> about whether he is using a macro or function, he just uses it.
> Common Lisp's CHECK-TYPE macro is a terrific example of this.  It
> doesn't really `seem' to be a macro.

For now, the reason for it being a macro escapes me. Well, ok, it
avoids having to quote the arguments. I must admit that I still
often have difficulty in understanding why the choices which have been
made in Common Lisp were made, when it comes to "hiding" the quote.

For example, I don't get why you need to quote the form passed to
MACROEXPAND. I don't mean to imply that I don't understand quoting in
Lisp; I mean that I don not understand why the choice was not made to
hide that quote by implementing MACROEXPAND as a macro. Do people pass
in forms for macroexpansion via variables? do they MAPCAR or APPLY
macroexpand?

On the other side of the coin, there have been a few occasions (though
exactly what they were, I forget) where I was using some macro which
does not evaluate some argument (seemingly to save you the hassle of
quoting a symbol), and found myself wishing that it would evaluate the
argument; it's all very nice not having to quote symbols, but it
removes the possibility of not quoting them, which you might want to
do if you want to pass the symbol in through a variable.

> But one reason CHECK-TYPE works so well is that it's focus on a single
> variable and type does not obviously lend itself to generalization.
> It doesn't seem like the kind of `function' you'd want to MAPCAR.

I can certainly imagine wanting to MAPCAR it in theory, but I accept
that I may not actually want to do so in practice.

> > This shouldn't be such an alien concept: when working interactively,
> > at the REPL, we keep calling macros at runtime. In Lisp, there is no
> > strict ordering and separation of macro expansion time -> compile time
> > -> run time, such as one finds in less flexible languages.
> 
> Yes, there is, but unlike less flexible languages, you do not need to
> blow away the runtime environment to relink in new code.  But macro
> expansion *always* (and logically *must*) preceed the execution of the
> macro form.  And obviously macro definition must preceed the
> expansion. 

Sure. I expressed myself badly. I meant to say that in many other
languages you first do _all_ macro expansion, then do _all_
compilation, and then proceed to execution; once you've done some
execution, there is no way that you will see any macroexpansion again
without, as you say, blowing away the whole runtime. In Lisp the
compiler and eval are available at runtime, so runtime events can
lead to further macroexpansion and compilation.

> It is useful to distinguish between `declaration' and execution.
> Although Lisp allows you to ignore this on the small scale (at the
> REPL) it should not be ignored on the large scale (when compiling a
> system).  Declaring forms such as DEFCLASS, DEFUN, DEFVAR,
> etc. instruct the compiler to arrange for the effect to be done when
> the file is loaded (or immediately after).  DEFUN doesn't create a
> function, it declares that after the file is loaded the named function
> will exist.  It is a subtle point because DEFUN at the REPL certainly
> *appears* to create a named function.

Thanks for the above; I hadn't thought of it that way before.

> >> Consider (mapcar 'macro (list 1 2 3)).  You are asking that a
> >> compile-time computation be applied to the run-time list value (1 2 3).
> >> What then, is the difference from a function?
> >
> > That is a question you would have to ask the implementor, not the
> > user.
> >
> >> Or perhaps that it be applied to the compile-time source code list value
> >> (list 1 2 3).  Yet macro functions are supposed to return valid lisp
> >> forms; what could this macro return that would be valid when fed to the
> >> compiler?
> >
> > As a user, I do not care. But I would hope that the final result is
> > equivalent to
> >
> > (list (macro 1) (macro 2) (macro 3))
> 
> Under what conditions would you hope this?

You've just made me realize something. I have probably given the
impression in this thread, by wirting the above, that I actually think
that this does, or wish that it would, or think that it should, happen
in Common Lisp. Nothing could be farther from the truth; I completely
understand that this does not happen and that it does not make any
sense. I originally wrote it in response to mrd's query as to what on
earth (mapcar 'macro (list 1 2 3)) would mean, a line of questioning
which was itself prompted by Tayssir John Gabour's suggestion that not
being able to mapcar over macros was not inherent in the macro
concept, but a consequence of the way macros are implemented in CL. I
assumed that it was clear that my "hope" was surrounded in a very
hypothetical context, rather than being a real hope in the context of
Common Lisp.

So, to answer your question, I would hope this in some (hypothetical)
language which is rather generous with the luxury of ignorance about
the macro/function nature of some operator.

> MACLISP had `fexprs' which were functions that did not evaluate their
> arguments, but even these would not help in this case.  Consider this:
> 
> (defun my-macro (&body body) `(quote ,(cadr body)))
> 
> (defun func-or-mac ()
>   (if (zerop (random 2)) #'identity #'my-macro))
> 
> ;; A really strange implementation of list.
> (defun foo (&rest args) (mapcar #'identity args))
> 
> (let ((a 1)
>       (b 2)
>       (c 3))
>   (mapcar (func-or-mac) (foo (+ a 2) (+ b 4) (+ c 6))))
> 
> If you map the function, you get the list (3 6 9), but 
> 
> (list (macro (+ a 2)) (macro (+ b 4)) (macro (+ c 6)))
> 
> would evaluate to the list (a b c).
> 
> Now how would the compiler arrange for this?  The source code for the
> macro to operate on could come from literally anywhere!  Must all code
> therefore keep around the original fragments of source code just in
> case someone tries to pass macro around?

Indeed, TJG hypothesised that something like this would need to happen
in the hypothetical situation that started all this.

> However, a COMPILER-MACRO is something that might interest you.  A
> COMPILER-MACRO is a mechanism by which you can inform the compiler how
> to optimize certain patterns of function usage.  You supply a function
> definition as normal (using DEFUN), but when the compiler notices a
> form that indicates a call to function, it invokes the COMPILER-MACRO
> for a possible rewrite.

Indeed, we've been discussing these elsewhere in the thread. I
expressed, there, a slight worry I have about compiler macros; their
use introduces alternative implementations of the same functionality
which get invoked in different situations. My fear is that subtle
mismatches in the functionality may lead to even subtler bugs. Any
comment ?

Thanks for your thoughtful post.
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87brk1cty6.fsf@nyct.net>
Jacek Generowicz <················@cern.ch> writes:

> Indeed, we've been discussing these elsewhere in the thread. I
> expressed, there, a slight worry I have about compiler macros; their
> use introduces alternative implementations of the same functionality
> which get invoked in different situations. My fear is that subtle
> mismatches in the functionality may lead to even subtler bugs. Any
> comment ?

Optimization is like that. The fact that you optimize floating-point
computations by using an FPU operation directly may lead to a bug where
you use the wrong opcode in the optimized version, but the generic
operator uses the right one. Recall the 3 rules of optimization.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Jacek Generowicz
Subject: Re: Dredging up patterns
Date: 
Message-ID: <tyfsmddgniq.fsf@pcepsft001.cern.ch>
Rahul Jain <·····@nyct.net> writes:

> Recall the 3 rules of optimization.

Which are yours ?

Mine are:

1. Don't do it.

2. Don't do it.

3. Don't do it yet.
From: Joe Marshall
Subject: Re: Dredging up patterns
Date: 
Message-ID: <d64hhrln.fsf@comcast.net>
Jacek Generowicz <················@cern.ch> writes:

> Rahul Jain <·····@nyct.net> writes:
>
>> Recall the 3 rules of optimization.
>
> Which are yours ?
>
> Mine are:
>
> 1. Don't do it.
>
> 2. Don't do it.
>
> 3. Don't do it yet.

Don't write non-optimal code?

-- 
~jrm
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87fz9a6eo2.fsf@nyct.net>
Joe Marshall <·············@comcast.net> writes:

> Jacek Generowicz <················@cern.ch> writes:
>
>> Rahul Jain <·····@nyct.net> writes:
>>
>>> Recall the 3 rules of optimization.
>>
>> Which are yours ?
>>
>> Mine are:
>>
>> 1. Don't do it.
>>
>> 2. Don't do it.
>>
>> 3. Don't do it yet.

Those are the ones I was talking about.

> Don't write non-optimal code?

That's the -1th rule.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87ekou6en8.fsf@nyct.net>
Joe Marshall <·············@comcast.net> writes:

> Jacek Generowicz <················@cern.ch> writes:
>
>> Rahul Jain <·····@nyct.net> writes:
>>
>>> Recall the 3 rules of optimization.
>>
>> Which are yours ?
>>
>> Mine are:
>>
>> 1. Don't do it.
>>
>> 2. Don't do it.
>>
>> 3. Don't do it yet.

Those are the ones I was talking about.

> Don't write non-optimal code?

That's the -1th rule.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Joe Marshall
Subject: Re: Dredging up patterns
Date: 
Message-ID: <brk1js75.fsf@comcast.net>
Jacek Generowicz <················@cern.ch> writes:

> Joe Marshall <·············@comcast.net> writes:
>
>> Jacek Generowicz <················@cern.ch> writes:
>> 
>> In Lisp, you can deliberately blur the syntactic distinction between
>> macro and function.  This can be used to good effect if it reduces the
>> intellectual burden on the user --- he doesn't need to think too hard
>> about whether he is using a macro or function, he just uses it.
>> Common Lisp's CHECK-TYPE macro is a terrific example of this.  It
>> doesn't really `seem' to be a macro.
>
> For now, the reason for it being a macro escapes me. Well, ok, it
> avoids having to quote the arguments. 

CHECK-TYPE signals a continuable error if the type is wrong so it has
to be able to modify (SETF) the place being checked.  If it were a
function, it could certainly check that the value was of the correct
type, but it would be unable to fix it.


> I must admit that I still often have difficulty in understanding why
> the choices which have been made in Common Lisp were made, when it
> comes to "hiding" the quote.

There is a lot of `historical baggage' in Common Lisp.  The SETQ form
originally derived from the SET form as a shortcut for 
(set (quote foo) ...)  In early Lisps, this would modify the value
cell of the symbol FOO.  But nowadays a SETQ form is just as likely to
be applied to a lexical variable.  In this case, a slot in an
environment structure or stack location is modified and any relation
to a symbol is incidental.

> For example, I don't get why you need to quote the form passed to
> MACROEXPAND.  I don't mean to imply that I don't understand quoting in
> Lisp; I mean that I don not understand why the choice was not made to
> hide that quote by implementing MACROEXPAND as a macro. 

Supposing that MACROEXPAND were a macro, how would it work?  It would
be a source->source transform that would walk the list structure of
source code and produce list structure.  It would likely be
*implemented* as a function that performed a transform on a list.
Rather than create a macro API to this function, the spec simply
requires that it be called `MACROEXPAND' and that the user can call it
directly if he wants to.  Basically, if you have macros, you have to
have a macro expansion facility and the raw unadorned entry point is
required to be called `macroexpand'. 

> Do people pass in forms for macroexpansion via variables? 

Sometimes.  The programatic use of macroexpand is pretty esoteric, but
you see it in code walkers like SCREAMER and SERIES.

> do they MAPCAR or APPLY macroexpand?

*very* rarely, but it happens.


> On the other side of the coin, there have been a few occasions (though
> exactly what they were, I forget) where I was using some macro which
> does not evaluate some argument (seemingly to save you the hassle of
> quoting a symbol), and found myself wishing that it would evaluate the
> argument; it's all very nice not having to quote symbols, but it
> removes the possibility of not quoting them, which you might want to
> do if you want to pass the symbol in through a variable.

I have run into this on occasion.

>> But one reason CHECK-TYPE works so well is that it's focus on a single
>> variable and type does not obviously lend itself to generalization.
>> It doesn't seem like the kind of `function' you'd want to MAPCAR.
>
> I can certainly imagine wanting to MAPCAR it in theory, but I accept
> that I may not actually want to do so in practice.

If you try it you'll see the problem.  Suppose FOO has four arguments
and all must be strings.  You might consider MAPing CHECK-TYPE:

(defun foo (a b c d)
  (mapcar (lambda (var)
            (check-type var string)) (list a b c d))
  ...

But this obviously checks the type of the variable VAR, not the
variables A B C D.

A `non-quoting' CHECK-TYPE won't help either:

(defun foo (a b c d)
  (check-type-nq 'a string)
  ...

This would be able to check the type of the value cell of the symbol
A, but that has nothing to do with the first argument to FOO.  (In
fact, it is equivalent to (check-type (symbol-value 'a) string) so you
gain nothing at all.)

> You've just made me realize something. I have probably given the
> impression in this thread, by wirting the above, that I actually think
> that this does, or wish that it would, or think that it should, happen
> in Common Lisp. Nothing could be farther from the truth; I completely
> understand that this does not happen and that it does not make any
> sense. 

You would be astounded at the nutcases that come to this group.  Last
year one nutcase asserted that in a backquote form since comma
`unquotes' a backquote that in a form such as  ',foo  the two `cancel'
and this is identical to FOO.  Now this is a simple misunderstanding
should be easily cleared up by just trying a few expansions:

(defvar *temp* '(x y z))

`(a b c (cdr *temp*) d e f)
=> (A B C (CDR *TEMP*) D E F)

`(a b c '(cdr *temp*) d e f)
=> (A B C (QUOTE (CDR *TEMP*)) D E F)

`(a b c ,(cdr *temp*) d e f)
=> (A B C (Y Z) D E F)

`(a b c (cdr ,*temp*) d e f)
=> (A B C (CDR (X Y Z)) D E F)

`(a b c ',(cdr *temp*) d e f)
=> (A B C (QUOTE (Y Z)) D E F)

It may be a little tricky for a neophyte to understand *why* you
might want the symbol QUOTE to appear in quoted output.

But this nutcase asserted that the above behavior is incorrect despite
the fact that

   - it is the behavior required of the spec

   - every conforming implementation does it this way

   - even non-conforming vaguely lisp-like languages do it this way

   - every experienced lisp hacker (including some authors of the
     spec) on this list told him that this was how it worked  

   - we referred him to papers explaining why this is the way it is

Essentially, he asserted that if reality did not match his
expectations, then reality was incorrect and he rejected it.

We really hope that questions are asked by somewhat rational people,
but we're frequently disappointed. 

>> However, a COMPILER-MACRO is something that might interest you.  A
>> COMPILER-MACRO is a mechanism by which you can inform the compiler how
>> to optimize certain patterns of function usage.  You supply a function
>> definition as normal (using DEFUN), but when the compiler notices a
>> form that indicates a call to function, it invokes the COMPILER-MACRO
>> for a possible rewrite.
>
> Indeed, we've been discussing these elsewhere in the thread. I
> expressed, there, a slight worry I have about compiler macros; their
> use introduces alternative implementations of the same functionality
> which get invoked in different situations. My fear is that subtle
> mismatches in the functionality may lead to even subtler bugs. Any
> comment ?

This can happen.  It is less common that you might think, though,
because the compiler macro can decline to expand, in which case the
compiler just turns it into a normal call to the function.  A typical
compiler macro often has this form:

(defun foo (a b)
   ...some implementation ...)

(define-compiler-macro foo (&whole form a b)
   (if (...some condition involving a and b...)
       `(...some expansion...)
       form))

So the compiler macro is written right next to the functional version
(this makes it easier to keep the two in sync) and the compiler macro
only expands if the subforms A and B meet some condition (like
SYMBOLP) where the expansion is easily seen to be correct.

I use compiler macros, but not frequently.  A large project may have a
handful for critical code where the advantage seriously outweighs any
potential risk.  For instance, in one project we had a function that
mapped over the slots in a versioned CLOS object.  We had lots of code
that did this:

(versioned-object-map-slots object
  (lambda (slot-name slot-value)
    ....))

This was terrific, but in an inner loop, the overhead of variable
access through the lexical environment made a difference.  I wrote a
compiler-macro that would rewrite that particular type of form to
this:

 (dolist (slot-definition (clos:class-slots (class-of OBJECT)))
   (let* ((SLOT-NAME (clos:slot-definition-name slot-definition))
          (boundp    (slot-boundp OBJECT SLOT-NAME)))
     (when boundp
       (let ((SLOT-VALUE (slot-value OBJECT SLOT-NAME)))
         (when (versioned-slot? SLOT-VALUE)
            ....)))))

This produced noticably faster code in the inner loop.


-- 
~jrm
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87n03l9wg4.fsf@nyct.net>
Joe Marshall <·············@comcast.net> writes:

>> do they MAPCAR or APPLY macroexpand?
>
> *very* rarely, but it happens.

If you're codewalking, you'd _always_ macroexpand all the parameter forms of
a function application.

(defun macroexpand-function-application (form)
  (cons (first form) (mapcar 'macroexpand (rest form))))

Of course, you'd probably want to rearrange the traversal to not re-cons
the whole code structure along the way just for kicks, but the idea is
reasonable.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: ·········@random-state.net
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c9n0fi$c98r2$1@midnight.cs.hut.fi>
Jacek Generowicz <················@cern.ch> wrote:

>> Common Lisp's CHECK-TYPE macro is a terrific example of this.  It
>> doesn't really `seem' to be a macro.

> For now, the reason for it being a macro escapes me. Well, ok, it
> avoids having to quote the arguments. I must admit that I still

Not needing to quote is an incidental benefit. The real issue is being
able to change the value in the lexical environment via the STORE-VALUE
restart:

 (defun foo (x)
    (check-type x symbol)
    (cons (symbol-package x) (symbol-name x)))

 (handler-bind ((error (lambda (e) (store-value :boing e))))
    (foo 42)) => (#<PACKAGE "KEYWORD"> . "BOING")

Cheers,

 -- Nikodemus                   "Not as clumsy or random as a C++ or Java. 
                             An elegant weapon for a more civilized time."
From: Peter Seibel
Subject: Re: Dredging up patterns
Date: 
Message-ID: <m34qq4s4lu.fsf@javamonkey.com>
Simon Adameit <·······@gmx.net> writes:

> Am Tue, 25 May 2004 14:53:33 -0400 schrieb mrd:
>
>> On Tue, 25 May 2004, Tayssir John Gabbour wrote:
>>> Pattern: Don't use macros.
>>> Problem: Ever try to mapcar over a macro in Common Lisp?
>>> Solution: Certain jaded outlook.
>> 
>> If you by patterns you mean "patterns of newbies" then yes, "trying to use
>> mapcar over a macro in CL" demonstrates a serious and fundamental
>> misunderstanding of the nature of macros.
>
> Does it? I think it's just a limitation of lisp's macros that they
> cant be passed around and not inherent in the macro concept. Though
> it would probably be terrebly inefficient and need access to the
> lexical environment to expand them at runtime.

Well, you can grab the macro expansion function using MACRO-FUNCTION
and use it at runtime if you really want. And if you can get ahold of
an environment object, the macro expansion function accepts it.
Otherwise pass NIL. Keep in mind that the first argument to a macro
expansion function is the whole form of the macro call.

  CL-USER> (defmacro backwards (&body body) `(progn ,@(reverse body)))
  BACKWARDS
  CL-USER> (apply (macro-function 'backwards) '((backwards (print 1) (print 2)) nil))
  (PROGN (PRINT 2) (PRINT 1))
  CL-USER> (mapcar (macro-function 'backwards) '((backwards (print 1) (print 2)) (backwards (print "a") (print "b"))) '(nil nil))
  ((PROGN (PRINT 2) (PRINT 1)) (PROGN (PRINT "b") (PRINT "a")))

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Lars Brinkhoff
Subject: Re: Dredging up patterns
Date: 
Message-ID: <85brkcqpbc.fsf@junk.nocrew.org>
Peter Seibel <·····@javamonkey.com> writes:
> Simon Adameit <·······@gmx.net> writes:
> >> On Tue, 25 May 2004, Tayssir John Gabbour wrote:
> >>> Pattern: Don't use macros.
> >>> Problem: Ever try to mapcar over a macro in Common Lisp?
> >>> Solution: Certain jaded outlook.
> > I think it's just a limitation of lisp's macros that they cant be
> > passed around and not inherent in the macro concept.
> Well, you can grab the macro expansion function using MACRO-FUNCTION
> and use it at runtime if you really want.

Just for fun:

  (set-dispatch-macro-character
   #\# #\`
   (lambda (s c n)
     `(lambda (&rest args) (eval (cons ',(read s t nil t) args)))))

(A more efficient compiling version is possible, but it still isn't a
terribly good idea.)

-- 
Lars Brinkhoff,         Services for Unix, Linux, GCC, HTTP
Brinkhoff Consulting    http://www.brinkhoff.se/
From: Pascal Costanza
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c907ts$j4o$1@newsreader2.netcologne.de>
Peter Seibel wrote:

> Well, you can grab the macro expansion function using MACRO-FUNCTION
> and use it at runtime if you really want. And if you can get ahold of
> an environment object, the macro expansion function accepts it.
> Otherwise pass NIL. Keep in mind that the first argument to a macro
> expansion function is the whole form of the macro call.

It's unlikely that you will be able to pass a useful environment object 
at runtime, because they have dynamic extent during macro expansion. See 
  Section 3.4.4 in the HyperSpec. That's the only real limitation - 
otherwise, it would work AFAICS.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: ·········@random-state.net
Subject: Re: Dredging up patterns
Date: 
Message-ID: <c908qi$bg8nh$1@midnight.cs.hut.fi>
Simon Adameit <·······@gmx.net> wrote:

>> If you by patterns you mean "patterns of newbies" then yes, "trying to use
>> mapcar over a macro in CL" demonstrates a serious and fundamental
>> misunderstanding of the nature of macros.

> Does it? I think it's just a limitation of lisp's macros that they cant be
> passed around and not inherent in the macro concept. Though it would

Macros abstract over syntax, hence I propose a new addition to the rich
oral tradition of "When FOO should net be a macro?":

 If (mapcar 'foo ...) makes sense, FOO should not be a macro.

Consider (mapcar 'when as bs). Does that mean:

 (loop for a in as
       for b in bs
       collect (when a b))

or

 (loop for a in as
       for b in bs
       collect (when (eval a) (eval b)))

?

Cheers,

  -- Nikodemus
From: Raffael Cavallaro
Subject: Re: Dredging up patterns
Date: 
Message-ID: <raffaelcavallaro-73F7E0.18035625052004@netnews.comcast.net>
In article <······························@gmx.net>,
 Simon Adameit <·······@gmx.net> wrote:


> Does it? I think it's just a limitation of lisp's macros that they cant be
> passed around and not inherent in the macro concept. Though it would
> probably be terrebly inefficient and need access to the lexical
> environment to expand them at runtime.

I hate to bring up scheme related material in c.l.l, but Oleg Kiselyov 
has an interesting paper entitled _Macros that Compose: Systematic Macro
Programming_ that might be of some interest in this context. Presumably, 
if one were working in such a system, mapcar would be a macro that knew 
how to compose with other macros properly.

<http://okmij.org/ftp/papers/Macros-talk.pdf>
From: Coby Beck
Subject: Re: Dredging up patterns
Date: 
Message-ID: <InTsc.11119$L.2746@news-server.bigpond.net.au>
"mrd" <·······@andrew.cmu.edu> wrote in message
·········································@unix45.andrew.cmu.edu...
> On Tue, 25 May 2004, Tayssir John Gabbour wrote:
> > Pattern: Don't use macros.
> > Problem: Ever try to mapcar over a macro in Common Lisp?
> > Solution: Certain jaded outlook.
>
> If you by patterns you mean "patterns of newbies" then yes, "trying to use
> mapcar over a macro in CL" demonstrates a serious and fundamental
> misunderstanding of the nature of macros.

I would expect it is more often being unmindful of which is which.  Now,
being *unhappy* that you can't, say, (apply #'and ....) might come from
misunderstanding what you are asking for!

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
From: Tayssir John Gabbour
Subject: Re: Dredging up patterns
Date: 
Message-ID: <866764be.0405260803.739a33b4@posting.google.com>
mrd <·······@andrew.cmu.edu> wrote in message news:<····································@unix45.andrew.cmu.edu>...
> On Tue, 25 May 2004, Tayssir John Gabbour wrote:
> > Pattern: Don't use macros.
> > Problem: Ever try to mapcar over a macro in Common Lisp?
> > Solution: Certain jaded outlook.
> 
> If you by patterns you mean "patterns of newbies" then yes, "trying to use
> mapcar over a macro in CL" demonstrates a serious and fundamental
> misunderstanding of the nature of macros.

Two things come to mind:
- Asking the hard, irrational questions is very useful for learning.
"Why isn't something this way?"

In fact, I got an interesting email about that mapcar/macros example,
which I just meant rhetorically.


- Patterns seem to cluster at the limits of a language. If I believe
patterns in other languages are about working around language
limitations, then I should look at lisp patterns to see where the
boundaries are drawn.

Why can't we write certain programs in any known language? Because of
halting problems and complexity limits. Algorithms occur at this
boundary. They're all about the limits of computation.

There seems to be a definite line between static and dynamic power in
CL.
http://www.ai.mit.edu/~gregs/ll1-discuss-archive-html/msg03947.html
From: Rahul Jain
Subject: Re: Dredging up patterns
Date: 
Message-ID: <87brk2pm8s.fsf@nyct.net>
···········@yahoo.com (Tayssir John Gabbour) writes:

> - Patterns seem to cluster at the limits of a language. If I believe
> patterns in other languages are about working around language
> limitations, then I should look at lisp patterns to see where the
> boundaries are drawn.

Hmm... what is the limitation of CL that makes it a pattern and not... 
something else... to have sequence operators take start and end keyword
parameters (which are interpreted in a specific way) to restrict the
operation to a specific slice of the sequence?

It's not the fact that array slices can't be passed around as
independent sequence objects, because they can be. Maybe it's the lack
of efficient dynamic-extent (actually allocated on the stack) displaced
arrays? Still, I don't know that I'd always end up using displaced
arrays when I want to limit a sequence operator to a specific portion of
the sequence.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: Tayssir John Gabbour
Subject: Re: Dredging up patterns
Date: 
Message-ID: <866764be.0405280552.512618d5@posting.google.com>
I wrote in message news:<····························@posting.google.com>...
> Has anyone really thought about "patterns" in lisp's context? By that
> I mean that whole Christopher Alexander thing Gabriel writes about in
> _Patterns of Software_.
> http://www.dreamsongs.com/NewFiles/PatternsOfSoftware.pdf

Incidentally, people might wish to know that Christopher Alexander's
new books are out. As he states in his preface to Patterns of
Software, "patterns" alone seemed to fail in helping people create
impressive architecture; he used the word "funky" a lot in describing
those creations. Mostly conventional, with some funkiness thrown in.

However, in that preface, he also states that he has evidence that
he's finally fulfilled that promise started with the patterns books,
and these new books seemed to have been released in 2003.
http://www.amazon.com/exec/obidos/tg/stores/series/-/55505/hardcover/ref=pd_serl_books/104-2063120-5580729

Expensive beasties, time to hit the library...
From: Steven E. Harris
Subject: Re: Dredging up patterns
Date: 
Message-ID: <q671xl4wg7n.fsf@L75001820.us.ray.com>
···········@yahoo.com (Tayssir John Gabbour) writes:

> these new books seemed to have been released in 2003.

They first went up for preorder in the Summer of 2001, with new
volumes trickling out about once every 10 months. Oddly enough, I have
volumes 1, 2, and 4 in hand; apparently the volume 3 is not done
yet. But, as backup, I also have a ~1100 page manuscript version from
when I took one of Professor Alexander's architecture classes on The
Nature of Order in 1992.

I'm almost done with the second volume, and regret to say that they
suffer from poor proofing. They contain a lot of typographical
mistakes, such as spelling errors, incorrectly numbered footnotes, and
other referential mismatches. Still, I'll take the material any way it
comes. Alexander has long been a hero of mine.

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com