Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Python syntax in Lisp and Scheme

48 views
Skip to first unread message

mik...@ziplip.com

unread,
Oct 3, 2003, 1:23:16 AM10/3/03
to
I think everyone who used Python will agree that its syntax is
the best thing going for it. It is very readable and easy
for everyone to learn. But, Python does not a have very good
macro capabilities, unfortunately. I'd like to know if it may
be possible to add a powerful macro system to Python, while
keeping its amazing syntax, and if it could be possible to
add Pythonistic syntax to Lisp or Scheme, while keeping all
of the functionality and convenience. If the answer is yes,
would many Python programmers switch to Lisp or Scheme if
they were offered identation-based syntax?

Paul Rubin

unread,
Oct 3, 2003, 1:51:33 AM10/3/03
to
mik...@ziplip.com writes:
> If the answer is yes, would many Python programmers switch to Lisp
> or Scheme if they were offered identation-based syntax?

I don't think the syntax is that big a deal. But programming in lisp
or scheme has a creaky feeling these days, because the traditional
runtime libraries in those languages have fallen so far behind the
times.

Dominic

unread,
Oct 3, 2003, 3:26:38 AM10/3/03
to

Well, there's always a programming language which has
more features than another. However documentation,
libraries, software-engineering tools and developer
community have also to be accounted for.

So whenever a special features is deemed necessary
but not available in the language I suggest to use
code generators.

E.g. you cannot express grammars in C/Java for
parsing so usually you stick to yacc/bison/flex/cups etc.

In C++ BOOST provides capabilites to express a parser
by means of template metaprogramming but compile times
are huge. In my opinion are old fashioned parser
generators more transparent.
So it's probably not worth the trouble.

I have successfuly implemented a simple code generator
for real-time control applications in Python
which outputs C-source.
http://www-user.rhrk.uni-kl.de/~hillbr/public/

Today I'd suggest to use XML-files to describe
the problem and generate source code from it.
Source code needed for assembling the final
result could also be embedded into the XML-files.

Eclipse uses a kind of JSP to generate code
from templates. (Examples exist
for generating source code for enumerations
which are not yet supported by Java)
However it's still very primitive.
At the rapid pace at which Eclipse
is developed I am curious what way it is going to take.


Ciao,
Dominic

prunes...@comcast.net

unread,
Oct 3, 2003, 3:47:16 AM10/3/03
to
mik...@ziplip.com writes:

> I think everyone who used Python will agree that its syntax is
> the best thing going for it.

I've used Python. I don't agree.

> It is very readable and easy
> for everyone to learn. But, Python does not a have very good
> macro capabilities, unfortunately. I'd like to know if it may
> be possible to add a powerful macro system to Python, while
> keeping its amazing syntax, and if it could be possible to
> add Pythonistic syntax to Lisp or Scheme, while keeping all
> of the functionality and convenience. If the answer is yes,
> would many Python programmers switch to Lisp or Scheme if
> they were offered identation-based syntax?

Yes, you would be able to add macros to Python. No, it isn't anywhere
as easy as it is with Lisp.

I imagine you could come up with a readtable hack for reading
pythonesque syntax in lisp. *shudder*

Tomasz Zielonka

unread,
Oct 3, 2003, 4:06:49 AM10/3/03
to
mik...@ziplip.com napisał:

> I think everyone who used Python will agree that its syntax is
> the best thing going for it. It is very readable and easy
> for everyone to learn. But, Python does not a have very good
> macro capabilities, unfortunately.

Well, there is Haskell which also offers indentation-base syntax and one
of it's compilers (GHC) recently added the Template Haskell extension.

This is a statically typed, non-strict purely functional language with
higher order and polymorphic functions, algebraic datatypes, etc. so
it's a BIT different than Python, but it's worth trying :)

PS. Haskell also allows to use {, } and ; instead of indentation. I
wonder why Python doesn't.

Best regards,
Tom

--
.signature: Too many levels of symbolic links

Tomasz Zielonka

unread,
Oct 3, 2003, 4:09:06 AM10/3/03
to
mik...@ziplip.com napisał:

> I think everyone who used Python will agree that its syntax is
> the best thing going for it. It is very readable and easy
> for everyone to learn. But, Python does not a have very good
> macro capabilities, unfortunately.

Well, there is Haskell which also offers indentation-based syntax and one
of its compilers (GHC) recently added the Template Haskell extension.

This is a statically typed, non-strict, purely functional language with


higher order and polymorphic functions, algebraic datatypes,

type-classes base overloading, etc. so it's a BIT different than Python,
but it's worth trying IMO.

Tomasz Zielonka

unread,
Oct 3, 2003, 4:10:11 AM10/3/03
to
mik...@ziplip.com napisał:

> I think everyone who used Python will agree that its syntax is
> the best thing going for it. It is very readable and easy
> for everyone to learn. But, Python does not a have very good
> macro capabilities, unfortunately.

Well, there is Haskell which also offers indentation-based syntax and


one
of its compilers (GHC) recently added the Template Haskell extension.

This is a statically typed, non-strict, purely functional language with
higher order and polymorphic functions, algebraic datatypes,

type-class based overloading, etc. so it's a BIT different than Python,
but it's worth trying IMO :)

Jeremy Yallop

unread,
Oct 3, 2003, 4:51:22 AM10/3/03
to
Tomasz Zielonka wrote:
> mik...@ziplip.com napisał:
>> I think everyone who used Python will agree that its syntax is
>> the best thing going for it.

I've used Python rather a lot, and I don't agree with this, FWIW.

> PS. Haskell also allows to use {, } and ; instead of indentation. I
> wonder why Python doesn't.

http://groups.google.com/groups?as_umsgid=199803092142.QAA04377%40fermi.eeel.nist.gov

Jeremy.

Tomasz Zielonka

unread,
Oct 3, 2003, 5:14:50 AM10/3/03
to
Jeremy Yallop wrote:
>> PS. Haskell also allows to use {, } and ; instead of indentation. I
>> wonder why Python doesn't.
>
> http://groups.google.com/groups?as_umsgid=199803092142.QAA04377%40fermi.eeel.nist.gov

A state of the art sophisticated parser? :)))

You almost got me. I don't know very much about Python and I had to
check that # is a beginning of a comment.

Do you know the meaning of 'instead of' ?

You still have to use indentation, right? You can't write:

if 1: #{ print 2 #} else: #{ print 3 #}

instead of

if 1: #{
print 2
#}
else: #{
print 3
#}

because that would be read as

if 1:

> Jeremy.

Alex Martelli

unread,
Oct 3, 2003, 6:08:57 AM10/3/03
to
Tomasz Zielonka wrote:

> mik...@ziplip.com napisa?:


>> I think everyone who used Python will agree that its syntax is
>> the best thing going for it. It is very readable and easy
>> for everyone to learn. But, Python does not a have very good
>> macro capabilities, unfortunately.
>
> Well, there is Haskell which also offers indentation-based syntax and
> one
> of its compilers (GHC) recently added the Template Haskell extension.

Of course, using that extension makes your Haskell programs unusable
with any other Haskell compilers (HUGS &c). Still, I found the
presentation (at ACCU/PythonUK) suitably mind-bending...;-)


> This is a statically typed, non-strict, purely functional language with
> higher order and polymorphic functions, algebraic datatypes,
> type-class based overloading, etc. so it's a BIT different than Python,
> but it's worth trying IMO :)

Seconded! It bends your mind in just the right way to expand it if
your background is in Python and other procedural and OO languages; it
shows you what strong static typing *SHOULD* be but too rarely is in
any other language; it offers just enough familiarity to Pythonistas
(we copied and adapted Haskell's list comprehensions, and the use of
significant indentation, independently developed in both languages, is
similar enough for comfort:-) to not feel completely lost (well, except
maybe when it comes to monads, but, there, almost _every_body gets lost,
so, don't despair if you do:-), and enough novel ideas that are usefully
applicable to Python coding (the "non-strict", aka lazy, evaluation that
is Haskell's defaults, you can implement e.g. with iterators in Python;
Haskell's typeclasses you can approximate with PEP-246 related ideas,
and they're heads and shoulders above the 'interfaces' or 'abstract
classes' of other languages; ...).


> PS. Haskell also allows to use {, } and ; instead of indentation. I
> wonder why Python doesn't.

>>> import this
The Zen of Python, by Tim Peters
...
There should be one-- and preferably only one --obvious way to do it.

Python is NOT about providing multiple alternative but roughly
equivalent "ways to do it": on the contrary, it TRIES to provide
ONE "obvious way to do it". That's roughly the same idea as given
among the "Principles of C", in the preface to the C standard, as
"Provide only one way to do an operation" (indeed, Python respects
about 4.5 of the 5 "Principles of C" -- many more than C++ or Java
do, and in that sense is much more philosophically compatible with
C). Among the advantages of the "preferably only one obvious way"
GOAL (it's not REACHED in practice, of course, but it's worth aiming
for!-) are the help in respecting the other principle "Keep the
language small and simple" (also from the "Principles of C") AND
the help in large, multi-people projects -- the fewer gratuitous
stylistic variations need to be accomodated, hammered out, and/or
compromised about in project-wide or firm-wide coding guidelines,
the earlier productive work on the project can start. I've seen
C coding projects spend WEEKS debating whether

if (blah) {
...
}

or

if (blah)
{
...
}

or other equivalent variations yet were to be accepted/recommended,
for example. Not that Python can fully remove such gratuitous
differences, but it sure doesn't strive to allow yet more -- this
helps the coding team's productivity by encouraging it to focus on
the stuff that DOES matter:-). [I have no experience of using
Haskell _in production_, say on projects requiring 10's of 1000's
of lines of code to be developed by a team of 10-12 developers
with widely different backgrounds, incorporating parts or wholes
of externally developed packages, so I have no idea about how
suitable it is for such projects -- I _do_ know that Python is a
delight to use for this kind of work, vastly preferable to other
languages I've used in such environments, including APL, Fortran,
several assembly languages, PL/I, C, Rexx, various Pascal dialects,
C++, Java, perl -- and the philosophical/cultural/community emphasis
on simplicity, clarity, uniformity, lack of "cleverness", and egoless
stances, helps with that as much as the technical characteristics do).


Alex

Mark Brady

unread,
Oct 3, 2003, 7:02:13 AM10/3/03
to
This whole thread is a bad idea. If you like python then use python.
Personally I find Scheme and Common Lisp easier to read but that's
just me, I prefer S-exps and there seems to be a rebirth in the Scheme
and Common Lisp communities at the moment. Ironically this seems to
have been helped by python. I learned python then got interested in
it's functional side and ended up learning Scheme and Common Lisp. A
lot of new Scheme and Common Lisp developers I talk to followed the
same route. Python is a great language and I still use it for some
things.

Paul Rubin's comments are just pure fud.

Some great scheme implementations with large modern libraries (not yet
a match for python but growing fast):
http://www.plt-scheme.org/
http://www-sop.inria.fr/mimosa/fp/Bigloo/
http://www.wikipedia.org/wiki/Gauche
http://sisc.sourceforge.net/
http://www.scheme.com/

Common Lisp has a fantastic wiki site (links to implementations and
loads of libraries) with everything you need to get started at:
http://www.cliki.net/index

Also see:
http://www.lisp.org/alu/home
http://common-lisp.net
http://www.cliki.net/YoungLispers

Many of the latest Scheme and Lisp mailing lists can be browsed from:
http://news.gmane.org/index.php?match=gmane.lisp

Develop in the language that suits you but despite the fud you do have
a choice,
Python, Scheme and Common Lisp are all fine languages with good
libraries and FFI capabilities.

Regards,
Mark.

Paul Rubin <http://phr...@NOSPAM.invalid> wrote in message news:<7xvfr6l...@ruckus.brouhaha.com>...

Matthias

unread,
Oct 3, 2003, 7:37:32 AM10/3/03
to
kal...@lycos.com (Mark Brady) writes:
> Paul Rubin's comments are just pure fud.
[...]

> Develop in the language that suits you but despite the fud you do have
> a choice,
> Python, Scheme and Common Lisp are all fine languages with good
> libraries and FFI capabilities.

I think that's incorrect: The Common Lisp language has no FFI (foreign
function call) capabilities. Each CL _implementation_ has one (which
is usually compatible to itself). This is exactly the reason why
there are way more libraries out there for Python, Perl, maybe Ruby
than for any single CL implementation. The same probably holds for
Scheme.

Toni Nikkanen

unread,
Oct 3, 2003, 7:44:36 AM10/3/03
to
kal...@lycos.com (Mark Brady) writes:

> just me, I prefer S-exps and there seems to be a rebirth in the Scheme
> and Common Lisp communities at the moment. Ironically this seems to
> have been helped by python. I learned python then got interested in
> it's functional side and ended up learning Scheme and Common Lisp.

It's be interesting to know where people got the idea of learning
Scheme/LISP from (apart from compulsory university courses)? I think
that for me, it was the LPC language used in LPmuds. It had a
frightening feature called lambda closures, and useful functions such
as map and filter. Then one day I just decided to bite the bullet and
find out where the heck all that stuff came from (my background was
strongly in C-like languages at that point. LPC is like C with some
object-oriented and some FP features.)

Yes, I know, there's nothing frightening in lambda closures. But the
way they were implemented in LPC (actually just the syntax) was
terrible :)

Alex Martelli

unread,
Oct 3, 2003, 8:40:36 AM10/3/03
to
mik...@ziplip.com wrote:

> I think everyone who used Python will agree that its syntax is
> the best thing going for it. It is very readable and easy
> for everyone to learn. But, Python does not a have very good
> macro capabilities, unfortunately. I'd like to know if it may
> be possible to add a powerful macro system to Python, while
> keeping its amazing syntax, and if it could be possible to

You can surely hack a "pre-processor" on top of the Python
interpreter. With the Python 2.3 architecture of import
hooks, it might even be quite feasible to experiment with
this idea as a pure Python package and distribute it as such:
just add a hook that scans incoming source files (modules)
for definitions and/or occurrences of the 'macros' you want,
and (respectively) squirrels away the definitions, and/or
expands the macros. As for designing the syntax for macro
definitions and expansions while remaining 'amazing', I'll
pass -- but surely it's not beyond human possibilities;-).

Anyway, see later in this post for a toy-level example.


> add Pythonistic syntax to Lisp or Scheme, while keeping all
> of the functionality and convenience. If the answer is yes,
> would many Python programmers switch to Lisp or Scheme if
> they were offered identation-based syntax?

If you could make all of the existing Python extensions,
libraries, frameworks, etc, instantly available from Lisp or
Scheme, you'd gain a LOT of kudos in the Lisp or Scheme
community, I suspect. That most existing Python coders
would be happy to leave the semantic simplicity of their
chosen language for the richness of Common Lisp, I very,
very strongly doubt, but in any case until the whole array
of existing extensions &c is available it's not an issue;-).


So, anyway, here's the promised toy-level example of using
custom importers with the new Python 2.3 mechanics to get
macros. I'm cutting corners to the bone (just to mix a
couple metaphors...) by using the C preprocessor (!) as my
"macro expander", ignoring packages, _and_ only looking for
"C-macro" definitions AND expansions in files with extension
".pyp" (all others, I'll leave alone...). Oh, also, I do
not worry about saving bytecode for such files -- I'm gonna
preprocess and recompile them on every run of the program
(far too much trouble, when macros exist, to determine
whether a bytecode file is up to date -- one should check
it, not only with respect to the date of ONE source file,
but rather of a hard-to-pin-down collection of macro and
include files... so, in the spirit of cutting corners and
keeping this a VERY toy-level example, I'm punting:-). So,
here's the gist...:


import sys
import os
import imp

prepro = 'cat %s | gcc -E -'

class MacroImporter(object):

def __init__(self, path):
self.path = path

def find_module(self, modname):
look_for_file = os.path.join(self.path, modname+'.pyp')
self.code = os.popen(prepro % look_for_file).read()
if self.code: return self
else: return None

def load_module(self, modname):
mod = imp.new_module(modname)
sys.modules[modname] = mod
mod.__file__ = "<Macro-Expanded %s>" % modname
exec self.code in mod.__dict__
return mod

sys.path_hooks.append(MacroImporter)

example = open('pippo.pyp', 'w')
example.write('''
#define unless(cond) if not(cond)
def pippo(x):
print 'x is', x
unless(x>=2): print ' x is smaller than two'
unless(x<=4): print ' x is bigger than four'
''')
example.close()

import pippo
pippo.pippo(1)
pippo.pippo(7)


Removing the various oversimplifications, and, in particular, designing
a better macro scheme than gcc -E supplies, is left as a trivial exercise
for the reader (I have in fact devised a perfect scheme, of course, but,
unfortunately, the margins of this post are too narrow for me to write it
down...).


Alex

Peter Hansen

unread,
Oct 3, 2003, 9:15:27 AM10/3/03
to
Tomasz Zielonka wrote:
>
> Jeremy Yallop wrote:
> >> PS. Haskell also allows to use {, } and ; instead of indentation. I
> >> wonder why Python doesn't.
> >
> > http://groups.google.com/groups?as_umsgid=199803092142.QAA04377%40fermi.eeel.nist.gov
>
> A state of the art sophisticated parser? :)))
>
> You almost got me. I don't know very much about Python and I had to
> check that # is a beginning of a comment.
>
> Do you know the meaning of 'instead of' ?
>
> You still have to use indentation, right? You can't write:
>
> if 1: #{ print 2 #} else: #{ print 3 #}

Even in standard C that would be considered poor style by most experienced
programmers. As the link said, "The use of indentation is considered
good coding practice in all these languages..."

Anyway, the question has been asked a zillion times before and any thread
on the subject risks being highly redundant, so don't even bother
discussing this further without first reading the last few years of
comp.lang.python. :-)

-Peter

Kenny Tilton

unread,
Oct 3, 2003, 9:33:25 AM10/3/03
to

Toni Nikkanen wrote:

> kal...@lycos.com (Mark Brady) writes:
>
>
>>just me, I prefer S-exps and there seems to be a rebirth in the Scheme
>>and Common Lisp communities at the moment. Ironically this seems to
>>have been helped by python. I learned python then got interested in
>>it's functional side and ended up learning Scheme and Common Lisp.
>
>
> It's be interesting to know where people got the idea of learning
> Scheme/LISP from (apart from compulsory university courses)?

<g> We wonder alike. That's why I started:

http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey

That recently got repotted from another cliki and it's a little mangled,
but until after ILC2003 I am a little too swamped to clean it up. But
there is still a lot of good stuff in there. On this page I grouped
folks according to different routes to Lisp (in the broadest sense of
that term): http://alu.cliki.net/The%20RtLS%20by%20Road

You will find some old-timers because I made the survey super-inclusive,
but my real interest was the same as yours: where are the New Lispniks
coming from?

Speaking of which, Mark Brady cited Python as a stepping-stone, and I
have been thinking that might happen, but the survey has yet to confirm.
Here's one: http://alu.cliki.net/Robbie%20Sedgewick's%20Road%20to%20Lisp

So Ping! Mark Brady, please hie ye (and all the others who followed the
same road to Lisp) to the survey and correct the record.

I think
> that for me, it was the LPC language used in LPmuds. It had a
> frightening feature called lambda closures, and useful functions such
> as map and filter. Then one day I just decided to bite the bullet and
> find out where the heck all that stuff came from (my background was
> strongly in C-like languages at that point. LPC is like C with some
> object-oriented and some FP features.)
>
> Yes, I know, there's nothing frightening in lambda closures. But the
> way they were implemented in LPC (actually just the syntax) was
> terrible :)

You could cut and paste that into the survey as well. :)

kenny

Terry Reedy

unread,
Oct 3, 2003, 9:36:32 AM10/3/03
to

"Mark Brady" <kal...@lycos.com> wrote in message
news:e840346c.03100...@posting.google.com...

> This whole thread is a bad idea.

I could agree that the OP's suggestion is a bad idea but do you
actually think that discussion and more publicity here for Lisp/Scheme
is bad? You make a pretty good pitch below for more Python=>Lisp
converts.

> If you like python then use python.

As I plan to do.

> Personally I find Scheme and Common Lisp easier to read but that's
> just me, I prefer S-exps and there seems to be a rebirth in the

cheme
> and Common Lisp communities at the moment. Ironically this seems to
> have been helped by python. I learned python then got interested in
> it's functional side and ended up learning Scheme and Common Lisp. A
> lot of new Scheme and Common Lisp developers I talk to followed the
> same route. Python is a great language and I still use it for some
> things.

Other Lispers posting here have gone to pains to state that Scheme is
not a dialect of Lisp but a separate Lisp-like language. Could you
give a short listing of the current main differences (S vs. CL)? If I
were to decide to expand my knowledge be exploring the current
versions of one(I've read the original SICP and LISP books), on what
basis might I make a choice?

Terry J. Reedy

ketil...@ii.uib.no

unread,
Oct 3, 2003, 9:39:59 AM10/3/03
to
Peter Hansen <pe...@engcorp.com> writes:

>> if 1: #{ print 2 #} else: #{ print 3 #}

> As the link said, "The use of indentation is considered

> good coding practice in all these languages..."

Hmmm, I really like the short one-liners like

let x = something in whatever x
foo (if bar then x else y) z

Even in C++, I could never sympathize with the newline
fundamentalists, insisting on sparse layout like:

if(p)
{
f(x);
}
else
{
g(x);
}

> Even in standard C [whitespace-poor layout] would be considered poor


> style by most experienced programmers.

Tough luck (but I don't expect to lose much sleep over it :-)

-kzm
--
If I haven't seen further, it is by standing in the footprints of giants

Toni Nikkanen

unread,
Oct 3, 2003, 9:42:53 AM10/3/03
to
Kenny Tilton <kti...@nyc.rr.com> writes:

> Speaking of which, Mark Brady cited Python as a stepping-stone, and I
> have been thinking that might happen, but the survey has yet to
> confirm.

It usually happens that when I google for some scheme/lisp-isms,
I get lots of Python mailing list messages as results. There's
something going on with that.

Kenny Tilton

unread,
Oct 3, 2003, 9:52:07 AM10/3/03
to

Kenny Tilton wrote:

>
>
> Toni Nikkanen wrote:
>
>> It's be interesting to know where people got the idea of learning
>> Scheme/LISP from (apart from compulsory university courses)?
>
>
> <g> We wonder alike. That's why I started:
>
> http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
>
> That recently got repotted from another cliki and it's a little mangled,
> but until after ILC2003 I am a little too swamped to clean it up.

Me and my big mouth. Now that I have adevrtised the survey far and wide,
and revisited it and seen up close the storm damage, sh*t, there goes
the morning. :) Well, I needed a break from RoboCells:

http://sourceforge.net/projects/robocells/

I am going to do what I can to fix up at least the road categorization,
and a quick glance revealed some great new entries, two that belong in
my Top Ten (with apologies to those getting bumped).

kenny

Tomasz Zielonka

unread,
Oct 3, 2003, 10:10:59 AM10/3/03
to
Peter Hansen wrote:
>> You still have to use indentation, right? You can't write:
>>
>> if 1: #{ print 2 #} else: #{ print 3 #}
>
> Even in standard C that would be considered poor style by most experienced
> programmers. As the link said, "The use of indentation is considered
> good coding practice in all these languages..."

In general I agree with you.

However there are (minor perhaps) situations where mandatory indentation
gets in the way. One such situation is when you are machine-generating
source code, but I suppose that there are some libraries helping with
that.

Other situation is when you are using an interactive interpreter - a
REPL. I tend to use Haskell (GHC) in this way a lot, and the possibility
to use {;} instead of intentation helps a lot.

The last one I can think of is in contests like Perl Golf, where the
objective is to write the shortest program performing given task.
We can probably all agree that this is not the best way to measure
goodness of language design. ;)

> -Peter

Lothar Scholz

unread,
Oct 3, 2003, 10:47:57 AM10/3/03
to
Paul Rubin <http://phr...@NOSPAM.invalid> wrote in message news:<7xvfr6l...@ruckus.brouhaha.com>...

Funny. Yesterday i downloaded the trial version of Franz Lisp (Allegro
CL).
I can'T say if the runtime libraries are out of date because there is
absolute no documentation for the runtime libraries - of course they
also bundle the ANSI-Common Lisp book.

I found that they still want to sell every fucking line of code in an
extra library raising the price to an unexceptable high value.

Jeremy H. Brown

unread,
Oct 3, 2003, 11:25:31 AM10/3/03
to
"Terry Reedy" <tjr...@udel.edu> writes:
> Other Lispers posting here have gone to pains to state that Scheme is
> not a dialect of Lisp but a separate Lisp-like language. Could you
> give a short listing of the current main differences (S vs. CL)?

According to the "Revised(5) Report on the Algorithmic Language
Scheme", "Scheme is a statically scoped and properly tail-recursive
dialect of the Lisp programming language..." It's certainly not a
dialect of Common Lisp, although it is one of CL's ancestors.

I'm sure if you do some web-groveling, you can find some substantial
comparisons of the two; I personally think they have more in common
than not. Here are a few of the (arguably) notable differences:

Scheme Common Lisp
Philosophy minimalism comprehensiveness
Namespaces one two (functions, variables)
Continuations yes no
Object system no yes
Exceptions no yes
Macro system syntax-rules defmacro
Implementations >10 ~4
Performance "worse" "better"
Standards IEEE ANSI
Reference name R5RS CLTL2
Reference length 50pp 1029pp
Standard libraries "few" "more"
Support Community Academic Applications writers

The Scheme community has the SRFI process for developing additional
almost-standards. I don't know if the CL community has something
equivalent; I don't think they did a year ago.

> If I were to decide to expand my knowledge be exploring the current
> versions of one(I've read the original SICP and LISP books), on what
> basis might I make a choice?

Try them both, see which one works for you in what you're doing.

Jeremy

Duane Rettig

unread,
Oct 3, 2003, 12:25:23 PM10/3/03
to
jhb...@ai.mit.edu (Jeremy H. Brown) writes:

> "Terry Reedy" <tjr...@udel.edu> writes:
> > Other Lispers posting here have gone to pains to state that Scheme is
> > not a dialect of Lisp but a separate Lisp-like language. Could you
> > give a short listing of the current main differences (S vs. CL)?

> I'm sure if you do some web-groveling, you can find some substantial
> comparisons of the two; I personally think they have more in common
> than not. Here are a few of the (arguably) notable differences:

This is actually a pretty good list. I'm not commenting on
completeness, but I do have a couple of corrections:

> Scheme Common Lisp
> Philosophy minimalism comprehensiveness
> Namespaces one two (functions, variables)
> Continuations yes no
> Object system no yes
> Exceptions no yes
> Macro system syntax-rules defmacro
> Implementations >10 ~4

===========================================^

See http://alu.cliki.net/Implementation - it lists 9 commercial
implementations, and 7 opensource implementations. There are
probably more.

> Performance "worse" "better"
> Standards IEEE ANSI
> Reference name R5RS CLTL2

============================================^

No, CLtL2 is definitely _not_ a reference for ANSI Common Lisp.
It was a snapshot taken in the middle of the ANSI process, and
is out of date in several areas. References which are much closer
to the ANSI spec can be found online at

http://www.franz.com/support/documentation/6.2/ansicl/ansicl.htm

or

http://www.lispworks.com/reference/HyperSpec/Front/index.htm

> Reference length 50pp 1029pp
> Standard libraries "few" "more"
> Support Community Academic Applications writers
>
> The Scheme community has the SRFI process for developing additional
> almost-standards. I don't know if the CL community has something
> equivalent; I don't think they did a year ago.

There are many grassroots defacto standards efforts to extend CL in
several areas. Some of these are listed here:

http://alu.cliki.net/Standard

> > If I were to decide to expand my knowledge be exploring the current
> > versions of one(I've read the original SICP and LISP books), on what
> > basis might I make a choice?
>
> Try them both, see which one works for you in what you're doing.

Agreed, but of course, I'd recommend CL :-)

--
Duane Rettig du...@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

Rayiner Hashem

unread,
Oct 4, 2003, 8:45:45 AM10/4/03
to
> Object system no yes
To be fair, most Scheme implementations come with one, and you can always
download an external one if you want.

> Macro system syntax-rules defmacro
Again, depends on the implementation. Gambit offers CL-style macros too.

> Performance "worse" "better"
Depends on the implementation. Bigloo did a bit better on the Great Computer
Language Shootout than did CMUCL, though, there were complaints that the
CL-code was sub-par. In the few small benchmarks I've tried on my machine,
Bigloo is pretty competitive with CMUCL.

Jeremy H. Brown

unread,
Oct 3, 2003, 1:53:05 PM10/3/03
to
Duane Rettig <du...@franz.com> writes:
> jhb...@ai.mit.edu (Jeremy H. Brown) writes:
> This is actually a pretty good list. I'm not commenting on
> completeness, but I do have a couple of corrections:
...

> > Implementations >10 ~4
> ===========================================^
>
> See http://alu.cliki.net/Implementation - it lists 9 commercial
> implementations, and 7 opensource implementations. There are
> probably more.

Thanks. I hadn't realized the spread was that large.

> > Performance "worse" "better"
> > Standards IEEE ANSI
> > Reference name R5RS CLTL2
> ============================================^
>
> No, CLtL2 is definitely _not_ a reference for ANSI Common Lisp.
> It was a snapshot taken in the middle of the ANSI process, and
> is out of date in several areas. References which are much closer
> to the ANSI spec can be found online at
>
> http://www.franz.com/support/documentation/6.2/ansicl/ansicl.htm
>
> or
>
> http://www.lispworks.com/reference/HyperSpec/Front/index.htm

Thanks again.

> >
> > Try them both, see which one works for you in what you're doing.
>
> Agreed, but of course, I'd recommend CL :-)

I've arrived at the conclusion that it depends both on your task/goal
and your personal inclinations.

Jeremy

Marco Antoniotti

unread,
Oct 3, 2003, 1:58:24 PM10/3/03
to

mik...@ziplip.com wrote:
> I think everyone who used Python will agree that its syntax is
> the best thing going for it. It is very readable and easy
> for everyone to learn. But, Python does not a have very good
> macro capabilities, unfortunately. I'd like to know if it may
> be possible to add a powerful macro system to Python, while
> keeping its amazing syntax, and if it could be possible to

> add Pythonistic syntax to Lisp or Scheme, while keeping all

> of the functionality and convenience. If the answer is yes,


> would many Python programmers switch to Lisp or Scheme if
> they were offered identation-based syntax?

Why do I feel like crying? :{

Cheers
--
Marco


Alexander Schmolck

unread,
Oct 3, 2003, 1:51:38 PM10/3/03
to
prunes...@comcast.net writes:

> mik...@ziplip.com writes:
>
> > I think everyone who used Python will agree that its syntax is
> > the best thing going for it.
>
> I've used Python. I don't agree.

I'd be interested to hear your reasons. *If* you take the sharp distinction
that python draws between statements and expressions as a given, then python's
syntax, in particular the choice to use indentation for block structure, seems
to me to be the best choice among what's currently on offer (i.e. I'd claim
that python's syntax is objectively much better than that of the C and Pascal
descendants -- comparisons with smalltalk, prolog or lisp OTOH are an entirely
different matter).

'as

Kenny Tilton

unread,
Oct 3, 2003, 2:00:44 PM10/3/03
to

Kenny Tilton wrote:

>
>
> Kenny Tilton wrote:
>
>>
>>
>> Toni Nikkanen wrote:
>>
>>> It's be interesting to know where people got the idea of learning
>>> Scheme/LISP from (apart from compulsory university courses)?
>>
>>
>>
>> <g> We wonder alike. That's why I started:
>>
>> http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
>>
>> That recently got repotted from another cliki and it's a little
>> mangled, but until after ILC2003 I am a little too swamped to clean it
>> up.
>
>
> Me and my big mouth. Now that I have adevrtised the survey far and wide,
> and revisited it and seen up close the storm damage, sh*t, there goes
> the morning. :)


OK, I copied over all the twenty-plus pages that got lost in the
repotting, fixed the survey questions, and even took the time to
annotate my Top Ten list:

http://alu.cliki.net/Kenny's%20RtLS%20Top-Ten

Check it out. The Switch Date pages have been restored, but I do not
think the cross-indexing works until pages get edited and resaved. That
is not the most fascinating breakdown in the world, so it may be a while
before I fuss with that. But this breakdown is cool:

http://alu.cliki.net/The%20RtLS%20by%20Road

More responses always welcome.

kenny

Terry Reedy

unread,
Oct 3, 2003, 2:23:13 PM10/3/03
to

"Jeremy H. Brown" <jhb...@ai.mit.edu> wrote in message
news:uv6brsy...@tenebrae.ai.mit.edu...
> "Terry Reedy" <tjr...@udel.edu> writes:
....

> > give a short listing of the current main differences (S vs. CL)?
...

> than not. Here are a few of the (arguably) notable differences:
...
Thank you. This is just the sort of preview I wanted.

> Try them both, see which one works for you in what you're doing.

My present interest is intellectual broadening. I think I should
start with parts of the current version of SICP and then read a modern
CL chapter on macros.

Terry J. Reedy

Joe Marshall

unread,
Oct 3, 2003, 2:38:21 PM10/3/03
to
Alexander Schmolck <a.sch...@gmx.net> writes:

(I'm ignoring the followup-to because I don't read comp.lang.python)

Indentation-based grouping introduces a context-sensitive element into
the grammar at a very fundamental level. Although conceptually a
block is indented relative to the containing block, the reality of the
situation is that the lines in the file are indented relative to the
left margin. So every line in a block doesn't encode just its depth
relative to the immediately surrounding context, but its absolute
depth relative to the global context. Additionally, each line encodes
this information independently of the other lines that logically
belong with it, and we all know that when some data is encoded in one
place may be wrong, but it is never inconsistent.

There is yet one more problem. The various levels of indentation
encode different things: the first level might indicate that it is
part of a function definition, the second that it is part of a FOR
loop, etc. So on any line, the leading whitespace may indicate all
sorts of context-relevant information. Yet the visual representation
is not only identical between all of these, it cannot even be
displayed.

Is this worse than C, Pascal, etc.? I don't know.
Worse than Lisp, Forth, or Smalltalk? Yes.

Mark Brady

unread,
Oct 3, 2003, 2:50:22 PM10/3/03
to
"Terry Reedy" <tjr...@udel.edu> wrote in message news:<7wednSJ_q_L...@comcast.com>...

> "Mark Brady" <kal...@lycos.com> wrote in message
> news:e840346c.03100...@posting.google.com...
> > This whole thread is a bad idea.
>
> I could agree that the OP's suggestion is a bad idea but do you
> actually think that discussion and more publicity here for Lisp/Scheme
> is bad? You make a pretty good pitch below for more Python=>Lisp
> converts.
>

You are right of course, however I dislike cross posting and I also
dislike blatantly arguing with people over language choice. I would
prefer to lead by example. I think one good program is worth a
thousand words. For example people listen to Paul Graham
(http://www.paulgraham.com/avg.html) when he advocates Common Lisp
because he wrote Viaweb using it and made a fortune thanks to Lisp's
features (details in the link).

> > If you like python then use python.
>
> As I plan to do.
>

Nothing wrong with that. Most people on these groups would agree that
Python is a very good choice for a wide range of software projects and
it is getting better with every release.

I think that if you can get over S-exps then Scheme and Common Lisp
feel very like python. I would recommend Pythonistas to at least
experiment with Common Lisp or Scheme even if you are perfectly happy
with Python. After all you have nothing to lose. If you don't like it
then fine you always have Python and you've probably learned something
and if you do like it then you have another language or two under your
belt.

> > Personally I find Scheme and Common Lisp easier to read but that's
> > just me, I prefer S-exps and there seems to be a rebirth in the
> cheme
> > and Common Lisp communities at the moment. Ironically this seems to
> > have been helped by python. I learned python then got interested in
> > it's functional side and ended up learning Scheme and Common Lisp. A
> > lot of new Scheme and Common Lisp developers I talk to followed the
> > same route. Python is a great language and I still use it for some
> > things.
>
> Other Lispers posting here have gone to pains to state that Scheme is
> not a dialect of Lisp but a separate Lisp-like language. Could you
> give a short listing of the current main differences (S vs. CL)? If I
> were to decide to expand my knowledge be exploring the current
> versions of one(I've read the original SICP and LISP books), on what
> basis might I make a choice?
>
> Terry J. Reedy


This is a difficult question to answer. It's a bit like trying to
explain the differences between Ruby and Python to a Java developer
;-)

*Personally* I find it best to think of Scheme and Common Lisp as two
different but very closely related languages. The actual languages and
communities are quite different.

Common Lisp is a large, very pragmatic, industrial strength language
and its community reflects this. Common Lisp has loads of features
that you would normally only get in add on libraries built right into
the language, it's object
system "CLOS" has to be experienced to be believed and its macro
system is stunning. Some very smart people have already put years of
effort into making it capable of great things such as Nasa's award
winning remote agent software
(http://ic.arc.nasa.gov/projects/remote-agent/).

Scheme is a more functional language and unlike Common Lisp is has a
single namespace for functions and variables (Python is like Scheme in
this regard). Common Lisp can be just as functional but on the whole
the Scheme community seem to embrace functional programming to a
greater extend.

Scheme is like python in that the actual language is quite small and
uses libraries for many of the same tasks Python would use them for,
unlike Common Lisp that has many of these features built into the
language. It also has a great but slightly different macro system
although every implementation I know also has Common Lisp style
Macros.

Scheme doesn't have a standard object system (it's more functional)
but has libraries to provide object systems. This is very hard to
explain to python developers, scheme is kind of like a big python
metaclass engine where different object systems can be used at will.
It's better than I can describe and it is really like a more powerful
version of Pythons metaclass system.

Pythonistas who love functional programming may prefer Scheme to
Common Lisp while Pythonistas who want a standard amazing object
system and loads of built in power in their language may prefer Common
Lisp.

To be honest the these tutorials will do a far better job than I
could:

For Scheme get DrScheme:
http://www.drscheme.org/

and go to

'Teach yourself scheme in fixnum days' :
http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html


For Common Lisp get the trial version of Lispworks:
http://www.lispworks.com/

and go get Mark Watsons free web book:
http://www.markwatson.com/opencontent/lisp_lic.htm

Regards,
Mark.

Ps. If anyone spots a mistake in this mail please correct me, it will
have been an honest one and not an attempt to slander your favourite
language and I will be glad to be corrected, in other words there is
no need to flame me :)

Edi Weitz

unread,
Oct 3, 2003, 3:29:45 PM10/3/03
to
On 03 Oct 2003 13:37:32 +0200, Matthias <n...@spam.pls> wrote:

> I think that's incorrect: The Common Lisp language has no FFI
> (foreign function call) capabilities. Each CL _implementation_ has
> one (which is usually compatible to itself). This is exactly the
> reason why there are way more libraries out there for Python, Perl,
> maybe Ruby than for any single CL implementation. The same probably
> holds for Scheme.

I'd say the Python /language/ also has no FFI capabilities. Either
that, or the Jython people are lying when they say that Jython "is an
implementation of the [...] language Python." (On the same website:
"Many of these modules are not yet implemented. Those coded in C for
CPython must be re-implemented in Java for Jython.")

Common Lisp and Scheme are languages defined by ANSI standards -
that's why you can have different implementations. Python, Perl, and
Ruby are defined by a reference implementation. You're comparing
apples and oranges.

Edi.

MetalOne

unread,
Oct 3, 2003, 5:45:11 PM10/3/03
to
kal...@lycos.com (Mark Brady) wrote in message news:<e840346c.03100...@posting.google.com>...

> Personally I find Scheme and Common Lisp easier to read but that's
> just me, I prefer S-exps ...

I am just barely familiar with Lisp and Scheme. However, I always
find comments like the above interesting. I have seen other people
make this claim also.
However, from an earlier post on comp.lang.python comparing a simple
loop.

Scheme
(define vector-fill!
(lambda (v x)
(let ((n (vector-length v)))
(do ((i 0 (+ i 1)))
((= i n))
(vector-set! v i x)))))

Python
def vector_fill(v, x):
for i in range(len(v)):
v[i] = x

To me the Python code is easier to read, and I can't possibly fathom
how somebody could think the Scheme code is easier to read. It truly
boggles my mind.

The second thing that puzzles me is the usage of the LISP macro
system. This system is touted as one of LISPs major strengths. I
believe the "Do" above is a macro. Is that the best syntax that can
be achieved with a macro for "Do". I would think there would already
be macros to write the Scheme code above in a format similar to the
Python code below, or some more readable syntax. I have looked for
repositories of such macros and I can't find any. This leads me to
think that in practice LISP macros are not used. Couple this with the
fact that LISP programmers seem happier with S-exprs, and I can't see
why a LISP programmer would even want to write a macro.

I have tried on 3 occassions to become a LISP programmer, based upon
the constant touting of LISP as a more powerful language and that
ultimately S-exprs are a better syntax. Each time, I have been
stopped because the S-expr syntax makes we want to vomit.

If a set of macros could be written to improve LISP syntax, then I
think that might be an amazing thing. An interesting question to me
is why hasn't this already been done.

felix

unread,
Oct 3, 2003, 6:01:34 PM10/3/03
to
On 03 Oct 2003 11:25:31 -0400, Jeremy H. Brown <jhb...@ai.mit.edu> wrote:

> I'm sure if you do some web-groveling, you can find some substantial
> comparisons of the two; I personally think they have more in common
> than not. Here are a few of the (arguably) notable differences:
>
> Scheme Common Lisp

> Namespaces one two (functions, variables)

Common Lisp has actually more than two namespaces.

> Implementations >10 ~4

There are loads more.

> Performance "worse" "better"

Nonsense.

> Support Community Academic Applications writers

Also nonsense.

>
> Try them both, see which one works for you in what you're doing.
>

Very good point.


cheers,
felix

Alex Martelli

unread,
Oct 3, 2003, 6:13:42 PM10/3/03
to
Mark Brady wrote:
...

> This is a difficult question to answer. It's a bit like trying to
> explain the differences between Ruby and Python to a Java developer
> ;-)

Been there, done that, it's not all _that_ difficult. The average Java
developer is quite able to understand the differences if you explain them
in terms of similarities and differences from Lisp ("Python has immutable
strings like Java, while Ruby's strings are mutable; Ruby has single
inheritance like Java, plus mix-ins, while Python has multiple inheritance,
with certain limitations", etc) and ability to interoperate ("Python has an
implementation that runs on a JVM, uses any Java class, and can generate
.class and .jar files just as if you had coded in Java, Ruby doesn't").

I think the "cultural" differences are subtler and more interesting (and
also, no doubt, even more debatable:-) -- the distinction between a Python
culture that takes pride in simplicity, uniformity, and avoidance of clever
tricks, versus a Ruby one that's quite different in these regards, IMHO.

Similarly, I suspect (but with even less reason to believe my observations
are correct) that the concept of a language being small and simple may be a
source of pride to the Scheme crowd (as it is, say, to the Python or C
ones), while that of a language being large and comprehensive may appeal to
Common Lispers (as it does, say, to C++ites or Perlmongers).

Such "soft-sciences" considerations may help guide one's choices about what
language to study next, I believe. E.g., a Pythonista who's looking for a
brisk "change of pace" might be more likely to find it in large-language
Common Lisp, while one who's looking for another "small, simple language"
culture might be more likely to find it in Scheme.


Alex

Peter Seibel

unread,
Oct 3, 2003, 6:13:27 PM10/3/03
to
j...@iteris.com (MetalOne) writes:

> kal...@lycos.com (Mark Brady) wrote in message news:<e840346c.03100...@posting.google.com>...
> > Personally I find Scheme and Common Lisp easier to read but that's
> > just me, I prefer S-exps ...
>
> I am just barely familiar with Lisp and Scheme. However, I always
> find comments like the above interesting. I have seen other people
> make this claim also. However, from an earlier post on
> comp.lang.python comparing a simple loop.
>
> Scheme
> (define vector-fill!
> (lambda (v x)
> (let ((n (vector-length v)))
> (do ((i 0 (+ i 1)))
> ((= i n))
> (vector-set! v i x)))))
>
> Python
> def vector_fill(v, x):
> for i in range(len(v)):
> v[i] = x
>
> To me the Python code is easier to read, and I can't possibly fathom
> how somebody could think the Scheme code is easier to read. It truly
> boggles my mind.

Well, over in comp.lang.lisp (where we speak Common Lisp, more so than
Scheme) we might write that:

(defun vector-fill (v x)
(dotimes (i (length v)) (setf (aref v i) x)))

or

(defun vector-fill (v x)
(loop for i below (length v)
do (setf (aref v i) x))) (defun vector-fill (v x)


which seems pretty similar to the Python version.

(If of course we didn't already have the FILL function that does just
that.)

> The second thing that puzzles me is the usage of the LISP macro
> system. This system is touted as one of LISPs major strengths. I
> believe the "Do" above is a macro. Is that the best syntax that can
> be achieved with a macro for "Do".

Nope. Common Lisp includes the standard macros DOTIMES and LOOP as
shown above.

> I would think there would already be macros to write the Scheme code
> above in a format similar to the Python code below, or some more
> readable syntax. I have looked for repositories of such macros and I
> can't find any.

I'm sure the Scheme folks will tell you were you can find such
repositories for Scheme. But Common Lisp has them built in.

> This leads me to think that in practice LISP macros are not used.

That is decidedly not true of Common Lisp.

> Couple this with the fact that LISP programmers seem happier with
> S-exprs, and I can't see why a LISP programmer would even want to
> write a macro.

Well, macros aren't intended to get you away from s-exps though the
LOOP macro does to a certain extent. They are just intended to get you
to more to-the-point s-exps. You put your finger right on it when you
wondered why there wasn't a better way to write your loop than DO. If
DOTIMES didn't already exist, you'd write it as a macro that expands
into DO. That is: DO is a almost completely general looping construct
which makes it more than you want in a lot of situations. Macros let
you turn what you want to write (DOTIMES) into the right version of
the more general, more powerful construct (DO).

> I have tried on 3 occassions to become a LISP programmer, based upon
> the constant touting of LISP as a more powerful language and that
> ultimately S-exprs are a better syntax. Each time, I have been
> stopped because the S-expr syntax makes we want to vomit.

Hmmm. If all three of those times have been with Scheme, you might
want to try Common Lisp for a change of pace.

> If a set of macros could be written to improve LISP syntax, then I
> think that might be an amazing thing. An interesting question to me
> is why hasn't this already been done.

Some (including me) would argue it has. They just don't define
"improve" as "get rid of all sexps".

-Peter

--
Peter Seibel pe...@javamonkey.com

Lisp is the red pill. -- John Fraser, comp.lang.lisp

Frode Vatvedt Fjeld

unread,
Oct 3, 2003, 6:22:47 PM10/3/03
to
j...@iteris.com (MetalOne) writes:

> [..] However, from an earlier post on comp.lang.python comparing a


> simple loop.
>
> Scheme
> (define vector-fill!
> (lambda (v x)
> (let ((n (vector-length v)))
> (do ((i 0 (+ i 1)))
> ((= i n))
> (vector-set! v i x)))))
>
> Python
> def vector_fill(v, x):
> for i in range(len(v)):
> v[i] = x
>
> To me the Python code is easier to read, and I can't possibly fathom
> how somebody could think the Scheme code is easier to read. It truly

> boggles my mind. [..]

The scheme example can only have been written by someone who is on the
outset determined to demonstrate that sexp-syntax is complicated. This
is how I'd write it in Common Lisp:

(defun vector-fill (v x)
(dotimes (i (length v))
(setf (aref v i) x)))

As you can see, it matches the python example quite closely.

> [..] If a set of macros could be written to improve LISP syntax,


> then I think that might be an amazing thing. An interesting
> question to me is why hasn't this already been done.

Lisp macros and syntactic abstractions are one of those things whose
power and elegance it is somewhat hard to explain to those who have
not experienced it themselves first hand. Paul Graham's book "On Lisp"
is considered by many to be a good introduction to the subject.

I am quite comforatble with Common Lisp's syntax, and I see no
particular need for some set of macros to improve its syntax. In fact
I have no idea what so ever as to what such a set of macros would look
like.

--
Frode Vatvedt Fjeld

Paul Rubin

unread,
Oct 3, 2003, 6:29:22 PM10/3/03
to
j...@iteris.com (MetalOne) writes:
> Scheme
> (define vector-fill!
> (lambda (v x)
> (let ((n (vector-length v)))
> (do ((i 0 (+ i 1)))
> ((= i n))
> (vector-set! v i x)))))

I think you could write the scheme code like this:

(define vector-fill! (v x)
(let ((i 0))
(while (< i (length v))
(vector-set! v i x)
(set! i (1+ i)))))

> I have tried on 3 occassions to become a LISP programmer, based upon
> the constant touting of LISP as a more powerful language and that
> ultimately S-exprs are a better syntax. Each time, I have been
> stopped because the S-expr syntax makes we want to vomit.

If you go crazy with macros, lisp gets confusing, that's for sure.

Daniel Silva

unread,
Oct 3, 2003, 6:32:57 PM10/3/03
to MetalOne
On Fri, 3 Oct 2003, MetalOne wrote:
> I am just barely familiar with Lisp and Scheme. However, I always
> find comments like the above interesting. I have seen other people
> make this claim also.
> However, from an earlier post on comp.lang.python comparing a simple
> loop.
>
> Scheme
> (define vector-fill!
> (lambda (v x)
> (let ((n (vector-length v)))
> (do ((i 0 (+ i 1)))
> ((= i n))
> (vector-set! v i x)))))
>
> Python
> def vector_fill(v, x):
> for i in range(len(v)):
> v[i] = x
>
> To me the Python code is easier to read, and I can't possibly fathom
> how somebody could think the Scheme code is easier to read. It truly
> boggles my mind.
>

I'd prefer one of these two implementations myself:

(define (vector-fill! v x)
(let loop ([i (sub1 (vector-length v))])
(unless (< i 0)
(vector-set! v i x)
(loop (sub1 i)))))

(define (vector-fill-again! v x)
(for-each (lambda (i)
(vector-set! v i x))
(build-list (vector-length v) identity)))


The second one actually does almost exactly what the Python version does,
other than creating a lambda and mapping identity across range(len(v)).

If you want to use macros to make a for-each that does just what your
example asks for:


(define-syntax (for stx)
(syntax-case stx ()
[(_ idx lst exp) #`(for-each (lambda (idx)
exp)
lst)]))

And given a function range that does the same thing:

(define (range r)
(build-list r identity))

Now you have the same for loop:

(define (my-vector-fill! v x)
(for i (range (vector-length v))
(vector-set! v i x)))


- Daniel

Erann Gat

unread,
Oct 3, 2003, 7:46:01 PM10/3/03
to
In article <92c59a2c.03100...@posting.google.com>,
j...@iteris.com (MetalOne) wrote:

> kal...@lycos.com (Mark Brady) wrote in message
news:<e840346c.03100...@posting.google.com>...
> > Personally I find Scheme and Common Lisp easier to read but that's
> > just me, I prefer S-exps ...
>
> I am just barely familiar with Lisp and Scheme. However, I always
> find comments like the above interesting. I have seen other people
> make this claim also.
> However, from an earlier post on comp.lang.python comparing a simple
> loop.
>
> Scheme
> (define vector-fill!
> (lambda (v x)
> (let ((n (vector-length v)))
> (do ((i 0 (+ i 1)))
> ((= i n))
> (vector-set! v i x)))))
>
> Python
> def vector_fill(v, x):
> for i in range(len(v)):
> v[i] = x
>
> To me the Python code is easier to read, and I can't possibly fathom
> how somebody could think the Scheme code is easier to read. It truly
> boggles my mind.

In Common Lisp you can write:

(defun vector-fill (v x)
(loop for i from 0 below (length v) do


(setf (aref v i) x)))

or

(defun vector-fill (v x)
(dotimes (i (length v))
(setf (aref v i) x)))

But if you focus on examples like this you really miss the point. Imagine
that you wanted to be able to write this in Python:

def vector_fill(v, x):
for i from 0 to len(v)-1:
v[i] = x

You can't do it because Python doesn't support "for i from ... to ...",
only "for i in ...". What's more, you can't as a user change the language
so that it does support "for i from ... to ...". (That's why the xrange
hack was invented.)

In Lisp you can. If Lisp didn't already have LOOP or DOTIMES as part of
the standard you could add them yourself, and the way you do it is by
writing a macro.

That's what macros are mainly good for, adding features to the langauge in
ways that are absolutely impossible in any other language. S-expression
syntax is the feature that enables users to so this quickly and easily.

> I can't see
> why a LISP programmer would even want to write a macro.

That's because you are approaching this with a fundamentally flawed
assumption. Macros are mainly not used to make the syntax prettier
(though they can be used for that). They are mainly used to add features
to the language that cannot be added as functions.

For example, imagine you want to be able to traverse a binary tree and do
an operation on all of its leaves. In Lisp you can write a macro that
lets you write:

(doleaves (leaf tree) ...)

You can't do that in Python (or any other langauge).

Here's another example of what you can do with macros in Lisp:

(with-collector collect
(do-file-lines (l some-file-name)
(if (some-property l) (collect l))))

This returns a list of all the lines in a file that have some property.
DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented
any other way because they take variable names and code as arguments.

E.


----

P.S. Here is the code for WITH-COLLECTOR and DO-FILE-LINES:

(defmacro with-collector (var &body body)
(let ( (resultvar (gensym "RESULT")) )
`(let ( (,resultvar '()) )
(flet ( (,var (item) (push item ,resultvar)) )
,@body)
(nreverse ,resultvar))))

(defmacro do-file-lines ((linevar filename &optional streamvar) &body body)
(let ( (streamvar (or streamvar (gensym "S"))) )
`(with-open-file (,streamvar ,filename)
(do ( (,linevar (read-line ,streamvar nil nil)
(read-line ,streamvar nil nil)) )
( (null ,linevar) )
,@body))))

Here's DOLEAVES:

(defmacro doleaves ((var tree) &body body)
`(walkleaves (lambda (,var) ,@body) ,tree))

:-)

(defun walkleaves (fn tree)
(iterate loop1 ( (tree tree) )
(if (atom tree)
(funcall fn tree)
(progn (loop1 (car tree)) (and (cdr tree) (loop1 (cdr tree)))))))

; This is the really cool way to iterate
(defmacro iterate (name args &rest body)
`(labels ((,name ,(mapcar #'car args) ,@body))
(,name ,@(mapcar #'cadr args))))

E.

Sampo Smolander

unread,
Oct 4, 2003, 2:53:37 AM10/4/03
to
In comp.lang.scheme Paul Rubin <http://phr...@nospam.invalid> wrote:
> I think you could write the scheme code like this:

> (define vector-fill! (v x)

I guess parenthesising like

(define (vector-fill! v x)

would be more schemey.

[Followups set to scheme-group only]

synthespian

unread,
Oct 4, 2003, 3:10:45 AM10/4/03
to
Jeremy H. Brown wrote:
(snip)

>
> According to the "Revised(5) Report on the Algorithmic Language
> Scheme", "Scheme is a statically scoped and properly tail-recursive
> dialect of the Lisp programming language..." It's certainly not a
> dialect of Common Lisp, although it is one of CL's ancestors.
>
> I'm sure if you do some web-groveling, you can find some substantial
> comparisons of the two; I personally think they have more in common
> than not. Here are a few of the (arguably) notable differences:
>
> Scheme Common Lisp
> Philosophy minimalism comprehensiveness

(etc)
Hello --

I would just like to point out that there's more choice out there in
the Lisp family than Scheme - Common Lisp.
In particular, I would like to mention ISLISP, which is an
ISO-standard Lisp. Apparently, the story goes somewhat like this: when
lispers went for an ANSI standard, they left out the Europeans and the
Japanese - which were the other people heavily using Lisp at the time.
Thus, ANSI Common Lisp was made all-American. So the people left out
went for an ISO-standard Lisp.
I don't know why this happened, I suspect (and I might be *very*
wrong) it had something to do with competition way back when Lisp were
aiming higher expectations market-wise (the French being very proud of
Prolog :-) ).
I have recently bumped into ISLISP. It is pretty good. It has full
documentation and two usable implementations: a GPL TISL, and a free for
non-commercial use OpenLisp (for now, at least, and I can't say for now
if this will change - for the better).
I don't have time to write a comparison table now, but let me just
say that it mentions in its documentation the purpose of merging the
perceived best features of "the family": "It attempts to bridge the gap
between the various incompatible members of the Lisp family of languages
(most notably Common Lisp, Eulisp, LeLisp, and Scheme) by focusing on
standardizing those areas of widespread agreement." (check the URLs
bellow, this quote from KMP's ISLISP site). However, it's not as big as
Common Lisp (but some people mention that Common Lisp is a large as it
is because it ported functionality that was from the Lisp Machines - but
I might be wrong, what do I know about Lisp Machines - I wish...).
ISLISP has objects, generic functions, defmacro and other good
things. One of its stated aims was industry-use, not academia (that's
from the spec).
The TISL implementation is not so much developed as OpenLisp, but
it's functional and GPLed. OpenLisp is lovely, and it beats the hell out
of Scheme and Common Lisp on the *huge* number of platforms it compiles
on. OpenLisp has compiled on over 60 platforms (yes! 16 to 64 bits!),
and is actively ported today to over 20! So, it's pretty amazing, when
you take into consideration that platform differences are an issue,
particularly with Common Lisp implementations (CLISP being the most
portable), when you need to interact with the OS. So, this is a
non-issue solved on OpenLisp, just as it is solved on Python or Perl. It
approaches Perl or Python in portability (or beats them, I dunno).
OpenLisp's author, unfortunately, isn't much of a "marketing" person...
I have tested it under win32 and NetBSD on Alpha.

BTW, I bumped into OpenLisp because of a Lisp-friendly unix shell
account provider,SDF Public Access Unix Network, a non-profit, that
supports OpenLisp for CGI (also having the usual Python/Perl, etc).
I mention ISLISP here because people are unaware of its existence,
and it's quite a jewel, really.
And let's be honest, who needs Python/Perl/Ruby when you have Lisp? ;-)

Well, that's my 2c, get to know and enjoy ISLISP.

Cheers,


Henry


OpenLisp by Eligis
http://christian.jullien.free.fr/
or http://www.eligis.com

TISL GPL'd ISLISP form Tohoku University (Japan) (under active development)
http://www.ito.ecei.tohoku.ac.jp/TISL/index_j.html

ISLISP - Standards http://anubis.dkuug.dk/JTC1/SC22/WG16/open/standard.html

More ISLISP documentation http://www.islisp.info/, this site maintained
by Kent Pitman

ISLISP in Java http://cube.misto.cz/lisp/

TBK's links on ISLISP
http://tkb.mpl.com/~tkb/links/tkb-links-2407134d0e19cfa20a5ebad3c416bc48.html

Grzegorz Chrupala

unread,
Oct 4, 2003, 3:17:30 AM10/4/03
to
j...@iteris.com (MetalOne) wrote in message news:<92c59a2c.03100...@posting.google.com>...

> Scheme
> (define vector-fill!
> (lambda (v x)
> (let ((n (vector-length v)))
> (do ((i 0 (+ i 1)))
> ((= i n))
> (vector-set! v i x)))))
>
> Python
> def vector_fill(v, x):
> for i in range(len(v)):
> v[i] = x
>
> To me the Python code is easier to read, and I can't possibly fathom
> how somebody could think the Scheme code is easier to read. It truly
> boggles my mind.

Pick a construct your pet language has specialized support, write an
ugly equivalent in a language that does not specifically support it
and you have proved your pet language to be superior to the other
language. (I myself have never used the "do" macro in Scheme and my
impression is few people do. I prefer "for-each", named "let" or the
CL-like "dotimes" for looping).
The point is if you want you can easily implement something like
"range" in Scheme (as shown by other posters). It would be more
illustrative choose an area where one of the languages is inherently
underpowered. For example I was shocked at how awkward Paul Graham's
"accumulator generator" snippet is in Python:

class foo:
def __init__(self, n):
self.n = n
def __call__(self, i):
self.n += i
return self.n


> If a set of macros could be written to improve LISP syntax, then I
> think that might be an amazing thing. An interesting question to me
> is why hasn't this already been done.

There are libraries that let you write Scheme in Python-like
indentation syntax (<URL:http://cliki.tunes.org/Scheme>, look for
Alternative Syntaxes). However, they are not widely used.

Cheers,
--
Grzegorz

synthespian

unread,
Oct 4, 2003, 3:36:25 AM10/4/03
to
Because it makes you wonder: "why?"

Henry

synthespian

unread,
Oct 4, 2003, 3:52:55 AM10/4/03
to
Mark Brady wrote:

> Pythonistas who love functional programming may prefer Scheme to
> Common Lisp while Pythonistas who want a standard amazing object
> system and loads of built in power in their language may prefer Common
> Lisp.
>

(snip)


> Regards,
> Mark.
>
> Ps. If anyone spots a mistake in this mail please correct me, it will
> have been an honest one and not an attempt to slander your favourite
> language and I will be glad to be corrected, in other words there is
> no need to flame me :)

I would just say that CLOS (Common Lisp Object System) is not "standard"
in the sense people take OOP to be nowadays, but able to encompass and
go beyond the JAVA, C++, Python, etc, paradigm. This fact was
demonstrated briefly on Paul Graham's ANSI Common LISP book, and
elsewhere, and it's basically a satori.

Henry

Alex Martelli

unread,
Oct 4, 2003, 4:45:41 AM10/4/03
to
Grzegorz Chrupala wrote:
...

> class foo:
> def __init__(self, n):
> self.n = n
> def __call__(self, i):
> self.n += i
> return self.n

some might prefer:

def foo(n):
tot = [n]
def acc(i):
tot[0] += i
return tot[0]
return acc

which is roughly equivalent. It's true that most Pythonistas prefer to
use class instances, rather than closures, in order to group together
some state and some behavior, and the language favours that; and Python
separates expressions and statements quite firmly, so one just can't
increment-and-return in one stroke, nor define-and-return-function ditto.
But I don't see how these issues spell "awkwardness" in this case.


Alex

Bengt Richter

unread,
Oct 4, 2003, 5:16:02 AM10/4/03
to
On 4 Oct 2003 00:17:30 -0700, grze...@pithekos.net (Grzegorz Chrupala) wrote:

>j...@iteris.com (MetalOne) wrote in message news:<92c59a2c.03100...@posting.google.com>...
>> Scheme
>> (define vector-fill!
>> (lambda (v x)
>> (let ((n (vector-length v)))
>> (do ((i 0 (+ i 1)))
>> ((= i n))
>> (vector-set! v i x)))))
>>
>> Python
>> def vector_fill(v, x):
>> for i in range(len(v)):
>> v[i] = x
>>

I guess you could also just write

v[:] = [x]*len(v)

instead of calling a function (though it takes more space), e.g.,

>>> v=range(10)
>>> id(v),v
(9442064, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> v[:] = [55]*len(v)
>>> id(v),v
(9442064, [55, 55, 55, 55, 55, 55, 55, 55, 55, 55])

using id(v) to show that the same object is mutated.

>> To me the Python code is easier to read, and I can't possibly fathom
>> how somebody could think the Scheme code is easier to read. It truly
>> boggles my mind.
>
>Pick a construct your pet language has specialized support, write an
>ugly equivalent in a language that does not specifically support it
>and you have proved your pet language to be superior to the other
>language. (I myself have never used the "do" macro in Scheme and my
>impression is few people do. I prefer "for-each", named "let" or the
>CL-like "dotimes" for looping).
>The point is if you want you can easily implement something like
>"range" in Scheme (as shown by other posters). It would be more
>illustrative choose an area where one of the languages is inherently
>underpowered. For example I was shocked at how awkward Paul Graham's
>"accumulator generator" snippet is in Python:
>
>class foo:
> def __init__(self, n):
> self.n = n
> def __call__(self, i):
> self.n += i
> return self.n
>

Do you like this better?

>>> def foo(n):
... box = [n]
... def foo(i): box[0]+=i; return box[0]
... return foo
...
>>> bar = foo(10)
>>> bar(1)
11
>>> bar(2)
13
>>> bar(37)
50
>>> baz = foo(100)
>>> bar(1), baz(23)
(51, 123)

>
>> If a set of macros could be written to improve LISP syntax, then I
>> think that might be an amazing thing. An interesting question to me
>> is why hasn't this already been done.
>
>There are libraries that let you write Scheme in Python-like
>indentation syntax (<URL:http://cliki.tunes.org/Scheme>, look for
>Alternative Syntaxes). However, they are not widely used.
>
>Cheers,
>--
>Grzegorz

Regards,
Bengt Richter

Alex Martelli

unread,
Oct 4, 2003, 5:44:58 AM10/4/03
to
Erann Gat wrote:
...

> But if you focus on examples like this you really miss the point. Imagine
> that you wanted to be able to write this in Python:
>
> def vector_fill(v, x):
> for i from 0 to len(v)-1:
> v[i] = x
>
> You can't do it because Python doesn't support "for i from ... to ...",
> only "for i in ...". What's more, you can't as a user change the language
> so that it does support "for i from ... to ...". (That's why the xrange
> hack was invented.)

Almost right, except that xrange is a hack. Since in Python you cannot
change the language to suit your whims, you USE the language (designed
by a pretty good language designer) -- by coding an iterator that is
suitable to put where the ... are in "for i in ...".

> In Lisp you can. If Lisp didn't already have LOOP or DOTIMES as part of
> the standard you could add them yourself, and the way you do it is by
> writing a macro.

Good summary: if you fancy yourself as a language designer, go for Lisp;
if you prefer to use a language designed by somebody else, without you
_or any of the dozens of people working with you on the same project_
being able to CHANGE the language, go for Python.

> That's what macros are mainly good for, adding features to the langauge in
> ways that are absolutely impossible in any other language. S-expression
> syntax is the feature that enables users to so this quickly and easily.

Doesn't Dylan do a pretty good job of giving essentially the same
semantics (including macros) without S-expression syntax? That was
my impression, but I've never used Dylan in production.

> For example, imagine you want to be able to traverse a binary tree and do
> an operation on all of its leaves. In Lisp you can write a macro that
> lets you write:
>
> (doleaves (leaf tree) ...)
>
> You can't do that in Python (or any other langauge).

Well, in Ruby, or Smalltalk, you would pass your preferred code block
to the call to the doleaves iterator, giving something like:

doleaves(tree) do |leaf|
...
end

while in Python, where iterators are "the other way around" (they
get relevant items out rather than taking a code block in), it would be:

for leaf in doleaves(tree):
...

In either case, it may not be "that" (you are not ALTERING the syntax
of the language, just USING it for the same purpose), but it's sure close.
(In Dylan, I do believe you could ``do that'' -- except the surface
syntax would not be Lisp-ish, of course).


> Here's another example of what you can do with macros in Lisp:
>
> (with-collector collect
> (do-file-lines (l some-file-name)
> (if (some-property l) (collect l))))
>
> This returns a list of all the lines in a file that have some property.
> DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented
> any other way because they take variable names and code as arguments.

If you consider than giving e.g. the variable name as an argument to
do-file-lines is the crucial issue here, then it's probably quite true
that this fundamental (?) feature "cannot be implemented any other way";
in Ruby, e.g., the variable name would not be an argument to dofilelines,
it would be a parameter at the start of the block receiving & using it:

dofilelines(somefilename) do |l|
collect l if someproperty? l
end

However, it appears to me that the focus on where variable names are
to be determined may be somewhat misplaced. The key distinction does
seem to be: if you're happy using a language as it was designed (e.g.,
in this example, respecting the language designer's concept that the
names for the control variables of a block must appear within | vertical
bars | at the start of the block -- or, in Python, the reversed concept
that they must appear between the 'for' and 'in' in the "for ... in ...:
statement), macros are not relevant; if you do want to design and use
your own language (including, for example, placing variable names in
new and interesting places) then macros can let you do that, while
other constructs would be insufficiently powerful.

If you dream of there being "preferably only one obvious way to do it",
as Pythonistas do (try "import this" at an interactive Python prompt),
macros are therefore a minus; if you revel in the possibilities of there
being many ways to do it, even ones the language designer had never even
considered (or considered and rejected in disgust:-), macros then become
a huge plus.

Therefore, I entirely agree that people who pine for macros should
use them in a language that accomodates them quite well, is designed
for them, cherishes and nurtures and exhalts them, like some language
of the Lisp family (be it Common, ISO, Scheme, ...), or perhaps Dylan
(which often _feels_ as if "of the Lisp family" even though it does
not use S-expressions), rather than trying to shoehorn them willy-nilly
into a language to whose overall philosophy they are SO utterly foreign,
like Python (Ruby, and even more Perl, may be a different matter;
google for "Lingua Latina Perligata" to see what Perl is already able
to do in terms of within-the-language language design and syntax
alteration, even without anything officially deemed to be 'macros'...
it IS, after all, a language CENTERED on "more than one way to do it").


Alex

Alan Crowe

unread,
Oct 4, 2003, 7:31:45 AM10/4/03
to
MetalOne wrote

> If a set of macros could be written to improve LISP
> syntax, then I think that might be an amazing thing. An
> interesting question to me is why hasn't this already been
> done.

I think the issue is the grandeur of the Lisp vision. More
ambitious projects require larger code bases. Ambition is
hard to quantify. Nevertheless one must face the issue of
scaling. Does code size go as the cube of ambition, or is it
the fourth power of ambition? Or something else entirely.

Lisp aspires to change the exponent, not the constant
factor. The constant factor is very important. That is why
CL has FILL :-) but shrinking the constant factor has been
done (and with C++ undone).

Macros can be used to abbreviate code. One can spot that one
is typing similar code over and over again. One says
"whoops, I'm typing macro expansions". Do you use macros to
tune the syntax, so that you type N/2 characters instead of
N characters, or do you capture the whole concept in macro
and eliminate the repetition altogether?

The point is that there is nowhere very interesting to go
with syntax tuning. It is the bolder goal of changing the
exponent, and thus seriously enlarging the realm of the
possible, that excites.

Alan Crowe

Frode Vatvedt Fjeld

unread,
Oct 4, 2003, 8:59:04 AM10/4/03
to al...@aleax.it
Alex Martelli <al...@aleax.it> writes:

> Good summary: if you fancy yourself as a language designer, go for
> Lisp; if you prefer to use a language designed by somebody else,
> without you _or any of the dozens of people working with you on the
> same project_ being able to CHANGE the language, go for Python.

I believe it is very unfortunate to view lisp macros as something that
is used to "change the language". Macros allow syntactic abstraction
the same way functions allow functional abstraction, and is almost as
important a part of the programmer's toolchest. While macros _can_ be
used to change the language in the sense of writing your own
general-purpose iteration construct or conditional operator, I believe
this is an abuse of macros, precisely because of the implications this
has for the readability of the code and for the language's user
community.

--
Frode Vatvedt Fjeld

David Rush

unread,
Oct 4, 2003, 8:11:49 AM10/4/03
to
On 03 Oct 2003 14:44:36 +0300, Toni Nikkanen <to...@tuug.fi> wrote:
> It's be interesting to know where people got the idea of learning
> Scheme/LISP from (apart from compulsory university courses)?

Emacs. I've noticed over the years that people don't really get Emacs
religion until they've started hacking elisp. I know that the frustration
of having almost-but-not-quite the behavior I wanted on top of having all
that source code was a powerful incentive for me to learn Lisp. Of course
my apreciation of Emacs only increased as I went...

The thing that sealed it for me was re-programming SCWM's behavior so that
I could use X w/no mouse &cet. That got me hooked on Scheme (I had been
hacking SML at roughly the same time while looking for the foundations of
OOP), which was really just about perfect semantically.

david rush
--
(\x.(x x) \x.(x x)) -> (s i i (s i i))
-- aki helin (on comp.lang.scheme)

Grzegorz Chrupala

unread,
Oct 4, 2003, 9:24:11 AM10/4/03
to
bo...@oz.net (Bengt Richter) wrote in message news:<blm34i$l6s$0...@216.39.172.122>...

> Do you like this better?
>
> >>> def foo(n):
> ... box = [n]
> ... def foo(i): box[0]+=i; return box[0]
> ... return foo
> ...

It's still a hack that shows an area where Python has unnecessary
limitations, isn't it?
As Paul Graham says (<URL:http://www.paulgraham.com/icad.html>):

> Python users might legitimately ask why they can't just write
>
> def foo(n):
> return lambda i: return n += i
>
> or even
>
> def foo(n):
> lambda i: n += i
>

Cheers,
-- Grzegorz

prunes...@comcast.net

unread,
Oct 4, 2003, 12:48:00 PM10/4/03
to

But syntactic abstractions *are* a change to the language, it just
sounds fancier.

I agree that injudicious use of macros can destroy the readability of
code, but judicious use can greatly increase the readability. So
while it is probably a bad idea to write COND1 that assumes
alternating test and consequence forms, it is also a bad idea to
replicate boilerplate code because you are eschewing macros.

Alex Martelli

unread,
Oct 4, 2003, 1:02:41 PM10/4/03
to
Grzegorz Chrupala wrote:
...

>> >>> def foo(n):
>> ... box = [n]
>> ... def foo(i): box[0]+=i; return box[0]
>> ... return foo
>> ...
>
> It's still a hack that shows an area where Python has unnecessary
> limitations, isn't it?

Debatable, and debated. See the "Rebinding names in enclosing
scopes" section of http://www.python.org/peps/pep-0227.html .

Essentially, Guido prefers classes (and instances thereof) to
closures as a way to bundle state and behavior; thus he most
emphatically does not want to add _any_ complication at all,
when the only benefit would be to have "more than one obvious
way to do it".

Guido's generally adamant stance for simplicity has been the
key determinant in the evolution of Python. Guido is also on
record as promising that the major focus in the next release
of Python where he can introduce backwards incompatibilities
(i.e. the next major-number-incrementing release, 3.0, perhaps,
say, 3 years from now) will be the _elimination_ of many of
the "more than one way to do it"s that have accumulated along
the years mostly for reasons of keeping backwards compatibility
(e.g., lambda, map, reduce, and filter, which Guido mildly
regrets ever having accepted into the language).


> As Paul Graham says (<URL:http://www.paulgraham.com/icad.html>):
>
>> Python users might legitimately ask why they can't just write
>>
>> def foo(n):
>> return lambda i: return n += i

The rule Python currently use to determine whether a variable
is local is maximally simple: if the name gets bound (assigned
to) in local scope, it's a local variable. Making this rule
*any* more complicated (e.g. to allow assignments to names in
enclosing scopes) would just allow "more than one way to do
it" (making closures a viable alternative to classes in more
cases) and therefore it just won't happen. Python is about
offering one, and preferably only one, obvious way to do it,
for any value of "it". And another key principle of the Zen
of Python is "simple is better than complex".

Anybody who doesn't value simplicity and uniformity is quite
unlikely to be comfortable with Python -- and this should
amply answer the question about the motivations for reason
number 1 why the above foo is unacceptable in Python (the
lambda's body can't rebind name n in an enclosing scope).

Python draws a firm distinction between expressions and
statements. Again, the deep motivation behind this key
distinction can be found in several points in the Zen of
Python, such as "flat is better than nested" (doing away
with the expression/statement separation allows and indeed
encourages deep nesting) and "sparse is better than dense"
(that 'doing away' would encourage expression/statements
with a very high density of operations being performed).

This firm distinction should easily explain other reasons
why the above foo is unacceptable in Python: n+=i is a
statement (not an expression) and therefore it cannot be
held by a 'return' keyword; 'return' is a statement and
therefore cannot be in the body of a 'lambda' keyword.

>> or even
>>
>> def foo(n):
>> lambda i: n += i

And this touches on yet another point of the Zen of Python:
explicit is better than implicit. Having a function
implicitly return the last expression it computes would
violate this point (and is in fact somewhat error-prone,
in my experience, in the several languages that adopt
this rule).

Somebody who is unhappy with this drive for explicitness,
simplicity, uniformity, and so on, cannot be happy with
Python. If he wants a very similar language from most
points of view, BUT with very different philosophies, he
might well be quite happy with Ruby. Ruby does away with
any expression/statement distinction; it makes the 'return'
optional, as a method returns the last thing it computes;
it revels in "more than one way to do it", clever and cool
hacks, not perhaps to the extent of Perl, but close enough.

In Ruby, the spaces of methods and data are separate (i.e.,
most everything is "an object" -- but, differently from
Python, methods are not objects in Ruby), and I do not
think, therefore, that you can write a method that builds
and returns another method, and bind the latter to a name --
but you can return an object with a .call method, a la:

def outer(a) proc do |b| a+=b end end

x = outer(23)
puts x.call(100) # emits 123
puts x.call(100) # emits 223

[i.e., I can't think of any way you could just use x(100)
at the end of such a snippet in Ruby -- perhaps somebody
more expert of Ruby than I am can confirm or correct...?]
but apart from this it seems closer to what the above
quotes appear to be probing for. In particular, it lets
you be MUCH, MUCH denser, if that is your purpose in life,
easily squeezing that outer function into a (short) line.
Python is NOT about making code very dense, indeed, as
above mentioned, it sees _sparseness_ as a plus; a typical
Pythonista would cringe at the density of that 'outer'
and by contrast REVEL at the "sparsity" and "explicitness"
(due to the many names involved:-) of, e.g.:

def make_accumulator(initial_value):
accumulator = Bunch(value=initial_value)
def accumulate(addend):
accumulator.value += addend
return accumulator.value
return accumulate

accumulate = make_accumulator(23)
print accumulate(100) # emits 123
print accumulate(100) # emits 223


(using the popular Bunch class commonly defined as:
class Bunch(object):
def __init__(self, **kwds):
self.__dict__.update(kwds)
). There is, of course, a cultural gulf between this
verbose 6-liner [using an auxiliary class strictly for
reasons of better readability...!] and the terse Ruby
1-liner above, and no doubt most practitioners of both
languages would in practice choose intermediate levels,
such as un-densifying the Ruby function into:


def outer(a)
proc do |b|
a+b
end
end

or shortening/densifying the Python one into:

def make_accumulator(a):
value = [a]
def accumulate(b):
value[0] += b
return value[0]
return accumulate

but I think the "purer" (more extreme) versions are
interesting "tipizations" for the languages, anyway.


Alex

Alex Martelli

unread,
Oct 4, 2003, 1:07:12 PM10/4/03
to
Frode Vatvedt Fjeld wrote:

> Alex Martelli <al...@aleax.it> writes:
>
>> Good summary: if you fancy yourself as a language designer, go for
>> Lisp; if you prefer to use a language designed by somebody else,
>> without you _or any of the dozens of people working with you on the
>> same project_ being able to CHANGE the language, go for Python.
>
> I believe it is very unfortunate to view lisp macros as something that
> is used to "change the language". Macros allow syntactic abstraction

Maybe "enhance" can sound more positive? An enhancement, of course,
IS a change -- and if one were to perform any change, he'd surely be
convinced it WAS going to be an enhancement. (Whether it really
turned out to be one is another issue).

> the same way functions allow functional abstraction, and is almost as
> important a part of the programmer's toolchest. While macros _can_ be
> used to change the language in the sense of writing your own
> general-purpose iteration construct or conditional operator, I believe
> this is an abuse of macros, precisely because of the implications this
> has for the readability of the code and for the language's user
> community.

Sure, but aren't these the examples that are being presented? Isn't
"with-collector" a general purpose iteration construct, etc? Maybe
only _special_ purpose ones should be built with macros (if you are
right that _general_ purpose ones should not be), but the subtleness
of the distinction leaves me wondering about the practice.


Alex


MetalOne

unread,
Oct 4, 2003, 1:19:33 PM10/4/03
to
Thanks for everybody's responses. I found them quite informative.

David Rush

unread,
Oct 4, 2003, 12:25:38 PM10/4/03
to
On Fri, 3 Oct 2003 09:36:32 -0400, Terry Reedy <tjr...@udel.edu> wrote:
> ... Lispers posting here have gone to pains to state that Scheme is
> not a dialect of Lisp but a separate Lisp-like language. Could you
> give a short listing of the current main differences (S vs. CL)?

Do you even begin to appreciate how inflammatory such a request is when
posted to to both c.l.l and c.l.s?

Anyway, as a fairly heavily biased Schemer:

Scheme vs Common Lisp

1 name space vs multiple name spaces
This is a bigger issue than it seems on the surface, BTW

#f vs nil
In Scheme an empty list is not considered to be the same
thing as boolean false

emphasis on all values being first-class vs ad-hoc values
Scheme tries to achieve this, Lisp is by conscious design a
compromise system design, for both good and bad

small semantic footprint vs large semantic footprint
Scheme seems relatively easier to keep in mind as an
additional language.CL appears to have several sub-languages
embedded in it. This cuts both ways, mind you.

Thos eare the most obvious surface issues. My main point is that it is
pretty much silly to consider any of the above in isolation. Both languages
make a lot of sense in their design context. I vastly prefer Scheme because
it suits my needs (small semantic footprint, powerful toolkit) far better
than CL (everything is there if you have the time to look for it). I should
point out that I build a lot of funny data structures (suffix trees and
other
IR magic) for which pre-built libraries are both exceedingly rare and
incorrectly optimized for the specific application.

I also like the fact that Scheme hews rather a lot closer to the
theoretical
foundations of CS than CL, but then again that's all part of the small
semantic
footprint for me.

Lulu of the Lotus-Eaters

unread,
Oct 4, 2003, 1:31:00 PM10/4/03
to
grze...@pithekos.net (Grzegorz Chrupala) wrote previously:

|shocked at how awkward Paul Graham's "accumulator generator" snippet is
|in Python:
|class foo:
| def __init__(self, n):
| self.n = n
| def __call__(self, i):
| self.n += i
| return self.n

Me too. The way I'd do it is probably a lot closer to the way Schemers
would do it:

>>> def foo(i, accum=[0]):
... accum[0]+=i
... return accum[0]
...
>>> foo(1)
1
>>> foo(3)
4

Shorter, and without an awkward class.

Yours, David...

--
Buy Text Processing in Python: http://tinyurl.com/jskh
---[ to our friends at TLAs (spread the word) ]--------------------------
Echelon North Korea Nazi cracking spy smuggle Columbia fissionable Stego
White Water strategic Clinton Delta Force militia TEMPEST Libya Mossad
---[ Postmodern Enterprises <me...@gnosis.cx> ]--------------------------


Alex Martelli

unread,
Oct 4, 2003, 2:06:17 PM10/4/03
to
Lulu of the Lotus-Eaters wrote:

> grze...@pithekos.net (Grzegorz Chrupala) wrote previously:
> |shocked at how awkward Paul Graham's "accumulator generator" snippet is
> |in Python:
> |class foo:
> | def __init__(self, n):
> | self.n = n
> | def __call__(self, i):
> | self.n += i
> | return self.n
>
> Me too. The way I'd do it is probably a lot closer to the way Schemers
> would do it:
>
> >>> def foo(i, accum=[0]):
> ... accum[0]+=i
> ... return accum[0]
> ...
> >>> foo(1)
> 1
> >>> foo(3)
> 4
>
> Shorter, and without an awkward class.

There's an important difference: with your approach, you cannot just
instantiate multiple independent accumulators like with the other --
a = foo(10)
b = foo(23)
in the 'class foo' approach, just as in all of those where foo returns an
inner-function instance, a and b are now totally independent accumulator
callables -- in your approach, 'foo' itself is the only 'accumulator
callable', and a and b after these two calls are just two numbers.

Making a cookie, and making a cookie-cutter, are quite different issues.


Alex

David Eppstein

unread,
Oct 4, 2003, 2:22:02 PM10/4/03
to
In article <mailman.1065288850...@python.org>,

Lulu of the Lotus-Eaters <me...@gnosis.cx> wrote:

> grze...@pithekos.net (Grzegorz Chrupala) wrote previously:
> |shocked at how awkward Paul Graham's "accumulator generator" snippet is
> |in Python:
> |class foo:
> | def __init__(self, n):
> | self.n = n
> | def __call__(self, i):
> | self.n += i
> | return self.n
>
> Me too. The way I'd do it is probably a lot closer to the way Schemers
> would do it:
>
> >>> def foo(i, accum=[0]):
> ... accum[0]+=i
> ... return accum[0]
> ...
> >>> foo(1)
> 1
> >>> foo(3)
> 4
>
> Shorter, and without an awkward class.

There's an important difference between these two: the object-based
solution (and the solutions with two nested functions and a closure)
allow more than one accumulator to be created. Yours only creates a
one-of-a-kind accumulator.

I happen to like the object-based solution better. It expresses more
clearly to me the intent of the code. I don't find the class awkward;
to me, a class is what you use when you want to keep some state around,
which is exactly the situation here. "Explicit is better than
implicit." Conciseness is not always a virtue.

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science

David Rush

unread,
Oct 4, 2003, 2:08:46 PM10/4/03
to
Since no one has done a point-by-point correction of the errors w/rt
Scheme...

On 03 Oct 2003 11:25:31 -0400, Jeremy H. Brown <jhb...@ai.mit.edu> wrote:
> Here are a few of the (arguably) notable differences:
>
> Scheme Common Lisp
> Philosophy minimalism comprehensiveness

orthogonality compromise

> Namespaces one two (functions, variables)
more than two, actually

> Continuations yes no
> Object system no yes

It really depends on how you define 'object system' as to whether or not
Scheme has one. I personally think it does, but you have to be prepared
to crawl around the foundations of OOP (and CS generally) before this
becomes apparent. It helps if you've ever lived with unconventional
object systems like Self.

> Exceptions no yes
yes, via continuations which reify the
fundamental control operators in all languages

> Macro system syntax-rules defmacro
most Schemes provide defmacro style macros as
they are relatively easy to implement correctly
(easier than syntax-rules anyway)

> Implementations >10 ~4
too many to count. The FAQ lists over twenty. IMO
there are about 9 'major' implementations which
have
relatively complete compliance to R5RS and/or
significant extension libraries

> Performance "worse" "better"
This is absolutely wrong. Scheme actually boasts
one
of the most efficient compliers on the planet in
the
StaLIn (Static Language Implementation) Scheme
system.
Larceny, Bigloo, and Gambit are also all quite
zippy
when compiled.

> Standards IEEE ANSI
Hrmf. 'Scheme' and 'Standard' are slightly skewed
terms.
This is probably both the greatest weakness of
the
language and also its greatest strength. R5RS is
more
of a description to programmers of how to write
portable
code than it is a constraint on implementors.
Scheme is
probably more of a "family" of languages than
Lisp is
at that.

Anyway, Nobody really pays much attention to
IEEE, although
that may change since it's being reworked this
year. The
real standard thus far has been the community
consensus
document called R5RS, the Revised^5 Report on the
Algorithmic
Language Scheme. There is a growing consensus
that it needs
work, but nobody has yet figured out how to make
a new version happen (And I believe that the IEEE effort is just
bringing IEEE up to date w/R5RS)

> Reference name R5RS CLTL2
> Reference length 50pp 1029pp
> Standard libraries "few" "more"
Well, we're up to SRFI-45 (admittedly a number of
them have been withdrawn, but the code and specification are still
available) and there's very little overlap.
Most of the SRFIs have highly portable
implementations.

> Support Community Academic Applications writers
in outlook, perhaps, but the academic component
has dropped fairly significantly over the years. The best implementations
still come out of academia, but the better libraries are starting to come
from people in the industry.
There is also an emphasis on heavily-armed
programming
which is sadly lacking in other branches of the
IT
industry. Remember - there is no Scheme
Underground.

Mario S. Mommer

unread,
Oct 4, 2003, 3:13:43 PM10/4/03
to

j...@iteris.com (MetalOne) writes:
> I have tried on 3 occassions to become a LISP programmer, based upon
> the constant touting of LISP as a more powerful language and that
> ultimately S-exprs are a better syntax. Each time, I have been
> stopped because the S-expr syntax makes we want to vomit.

:-)

Although people are right when they say that S-exprs are simpler, and
once you get used to them they are actually easier to read, I think
the visual impact they have on those not used to it is often
underestimated.

And to be honest, trying to deal with all these parenthesis in an
editor which doesn't help you is not an encouraging experience, to say
the least. You need at least a paren-matching editor, and it is a real
big plus if it also can reindent your code properly. Then, very much
like in python, the indent level tells you exactly what is happening,
and you pretty much don't see the parens anymore.

Try it! In emacs, or Xemacs, open a file ending in .lisp and
copy/paste this into it:

;; Split a string at whitespace.
(defun splitatspc (str)
(labels ((whitespace-p (c)
(find c '(#\Space #\Tab #\Newline))))
(let* ((posnew -1)
(posold 0)
(buf (cons nil nil))
(ptr buf))
(loop while (and posnew (< posnew (length str))) do
(setf posold (+ 1 posnew))
(setf posnew (position-if #'whitespace-p str
:start posold))
(let ((item (subseq str posold posnew)))
(when (< 0 (length item))
(setf (cdr ptr) (list item))
(setf ptr (cdr ptr)))))
(cdr buf))))

Now place the cursor on the paren just in front of the defun in the
first line, and hit ESC followed by <ctrl-Q>.

> If a set of macros could be written to improve LISP syntax, then I
> think that might be an amazing thing. An interesting question to me
> is why hasn't this already been done.

Because they are so damned regular. After some time you do not even
think about the syntax anymore.

Frode Vatvedt Fjeld

unread,
Oct 4, 2003, 3:41:55 PM10/4/03
to
prunes...@comcast.net writes:

> But syntactic abstractions *are* a change to the language, it just
> sounds fancier.

Yes, this is obviously true. Functional abstractions also change the
language, even if it's in a slightly different way. Any programming
language is, after all, a set of functional and syntactic
abstractions.

> I agree that injudicious use of macros can destroy the readability
> of code, but judicious use can greatly increase the readability. So
> while it is probably a bad idea to write COND1 that assumes
> alternating test and consequence forms, it is also a bad idea to
> replicate boilerplate code because you are eschewing macros.

I suppose this is about the same differentiantion I wanted to make by
the terms "syntactic abstraction" (stressing the idea of building a
syntax that matches a particular problem area or programming pattern),
and "changing the language" which is just that, not being part of any
particular abstraction other than the programming language itself.

--
Frode Vatvedt Fjeld

Terry Reedy

unread,
Oct 4, 2003, 3:49:06 PM10/4/03
to
"David Rush" <dr...@aol.net> wrote in message
news:oprwi080...@news.nscp.aoltw.net...

> On Fri, 3 Oct 2003 09:36:32 -0400, Terry Reedy <tjr...@udel.edu>
wrote:
> > ... Lispers posting here
By 'here', I meant comp.lang.python ...

>> have gone to pains to state that Scheme is
> > not a dialect of Lisp but a separate Lisp-like language. Could
you
> > give a short listing of the current main differences (S vs. CL)?

> Do you even begin to appreciate how inflammatory such a request is
> when posted to to both c.l.l and c.l.s?

As implied by 'here', I did not originally notice the cross-posting
(blush, laugh ;<). I am pleased with the straightforward, civil, and
helpful answers I have received, including yours, and have saved them
for future reference.

...


> compromise system design, for both good and bad

...


> embedded in it. This cuts both ways, mind you.

...

I believe in neither 'one true religion' nor in 'one best
algorithm/computer language for all'. Studying Lisp has helped me
better understand Python and the tradeoffs embodied in its design. I
certainly better appreciate the issue of quoting and its relation to
syntax.

Terry J. Reedy


Ed Avis

unread,
Oct 4, 2003, 3:46:26 PM10/4/03
to
mik...@ziplip.com writes:

>I'd like to know if it may be possible to add a powerful macro system
>to Python, while keeping its amazing syntax,

I fear it would not be. I can't say for certain but I found that the
syntax rules out nesting statements inside expressions (without adding
some kind of explicit bracketing, which rather defeats the point of
Python syntax) and you might run into similar difficulties if adding
macros. It's a very clean syntax (well, with a few anomalies) but
this is at the price of a rigid separation between statements and
expressions, which doesn't fit well with the Lisp-like way of doing
things.

Myself I rather like the option chosen by Haskell, to define an
indentation-based syntax which is equivalent to one with bracketing,
and let you choose either. You might do better to add a new syntax to
Lisp than to add macro capabilities to Python. Dylan is one Lisp
derivative with a slightly more Algol-like syntax, heh, Logo is
another; GNU proposed some thing called 'CTAX' which was a C-like
syntax for Guile Scheme, I don't know if it is usable.

If the indentation thing appeals, maybe you could preprocess Lisp
adding a new kind of bracket - say (: - which closes at the next line
of code on the same indentation level. Eg

(: hello
there
(goodbye)

would be equivalent to

(hello
there)
(goodbye)

I dunno, this has probably already been done.

--
Ed Avis <e...@membled.com>

Frode Vatvedt Fjeld

unread,
Oct 4, 2003, 4:11:49 PM10/4/03
to al...@aleax.it
Alex Martelli <al...@aleax.it> writes:

> Sure, but aren't these the examples that are being presented? Isn't
> "with-collector" a general purpose iteration construct, etc? Maybe
> only _special_ purpose ones should be built with macros (if you are
> right that _general_ purpose ones should not be), but the subtleness
> of the distinction leaves me wondering about the practice.

It is a subtle distinction, just like a lot of other issues in
programming are quite subtle. And I think this particular issue
deserves more attention than it has been getting (so far as I know).

As for the current practice, I know that I quite dislike code that
uses things like with-collector, and I especially dislike it when I
have to look at the macro's expansion to see what is going on, and I
know there are perfectly fine alternatives in the standard syntax. On
the other hand, I do like it when I see a macro call that reduces tens
or even hundreds of lines of code to just a few lines that make it
immediately apparent what's happening. And I know I'd never want to
use a language with anything less than lisp's macros.

--
Frode Vatvedt Fjeld

Sander Vesik

unread,
Oct 4, 2003, 6:22:12 PM10/4/03
to
In comp.lang.scheme Grzegorz Chrupala <grze...@pithekos.net> wrote:
> j...@iteris.com (MetalOne) wrote in message news:<92c59a2c.03100...@posting.google.com>...
>> Scheme
>> (define vector-fill!
>> (lambda (v x)
>> (let ((n (vector-length v)))
>> (do ((i 0 (+ i 1)))
>> ((= i n))
>> (vector-set! v i x)))))
>>
>> Python
>> def vector_fill(v, x):
>> for i in range(len(v)):
>> v[i] = x
>>
>> To me the Python code is easier to read, and I can't possibly fathom
>> how somebody could think the Scheme code is easier to read. It truly
>> boggles my mind.
>
> Pick a construct your pet language has specialized support, write an
> ugly equivalent in a language that does not specifically support it
> and you have proved your pet language to be superior to the other
> language. (I myself have never used the "do" macro in Scheme and my
> impression is few people do. I prefer "for-each", named "let" or the
> CL-like "dotimes" for looping).

Whiile true, if solving a problem requires you to use a lot of constructs
that one language provides and for which youave to do lots of extra work
in teh other, one might aswell take the pragmatic approach that the other
language is better for the given problem at hand.

>
> Cheers,
> --
> Grzegorz

--
Sander

+++ Out of cheese error +++

Sander Vesik

unread,
Oct 4, 2003, 6:55:21 PM10/4/03
to
In comp.lang.scheme David Rush <dr...@aol.net> wrote:
> On 03 Oct 2003 14:44:36 +0300, Toni Nikkanen <to...@tuug.fi> wrote:
>> It's be interesting to know where people got the idea of learning
>> Scheme/LISP from (apart from compulsory university courses)?
>
> Emacs. I've noticed over the years that people don't really get Emacs
> religion until they've started hacking elisp. I know that the frustration
> of having almost-but-not-quite the behavior I wanted on top of having all
> that source code was a powerful incentive for me to learn Lisp. Of course
> my apreciation of Emacs only increased as I went...

I have at times almost gnawed off my hand to avoid going down that path.
I'd rather write cobol than elisp...

>
> The thing that sealed it for me was re-programming SCWM's behavior so that
> I could use X w/no mouse &cet. That got me hooked on Scheme (I had been
> hacking SML at roughly the same time while looking for the foundations of
> OOP), which was really just about perfect semantically.
>
> david rush

--

Kenny Tilton

unread,
Oct 4, 2003, 7:10:00 PM10/4/03
to

Sander Vesik wrote:
> I have at times almost gnawed off my hand to avoid going down that path.
> I'd rather write cobol than elisp...

Mileage does vary :): http://alu.cliki.net/RtL%20Emacs%20Elisp

That page lists people who actually cite Elisp as at least one way they
got turned on to Lisp. I started the survey when newbies started showing
up on the c.l.l. door in still small but (for Lisp) significantly larger
numbers. Pail Graham holds a commanding lead, btw.

kenny

Paul Rubin

unread,
Oct 4, 2003, 7:23:22 PM10/4/03
to
Kenny Tilton <kti...@nyc.rr.com> writes:
> That page lists people who actually cite Elisp as at least one way
> they got turned on to Lisp. I started the survey when newbies started
> showing up on the c.l.l. door in still small but (for Lisp)
> significantly larger numbers. Pail Graham holds a commanding lead, btw.

I'd fooled around with other lisp systems before using GNU Emacs, but
reading the Emacs source code was how I first got to really understand
how Lisp works.

David Eppstein

unread,
Oct 4, 2003, 7:46:36 PM10/4/03
to
In article <crIfb.14315$pv6....@twister.nyc.rr.com>,
Kenny Tilton <kti...@nyc.rr.com> wrote:

Heh. Does that mean former TECO programmers will get turned on to Perl?
Hasn't had that effect for me yet...

Sander Vesik

unread,
Oct 4, 2003, 7:59:22 PM10/4/03
to
In comp.lang.scheme David Rush <dr...@aol.net> wrote:
>
>> Exceptions no yes
> yes, via continuations which reify the
> fundamental control operators in all languages

the exceptions SRFI and saying it is there as an extension would imho be a
better answer.

>
>> Implementations >10 ~4
> too many to count. The FAQ lists over twenty. IMO
> there are about 9 'major' implementations which
> have
> relatively complete compliance to R5RS and/or
> significant extension libraries
>

And the number is likely to continue increase over the years. Scheme is
very easy to implement, including as an extensions language inside the
runtime of something else. The same doesn't really hold for common lisp.

Rene van Bevern

unread,
Oct 5, 2003, 4:04:10 AM10/5/03
to
On Sat, 04 Oct 2003 13:11:49 +0100, David Rush <dr...@aol.net> wrote:
> Emacs. I've noticed over the years that people don't really get Emacs
> religion until they've started hacking elisp. I know that the frustration
> of having almost-but-not-quite the behavior I wanted on top of having all
> that source code was a powerful incentive for me to learn Lisp. Of course
> my apreciation of Emacs only increased as I went...

hm. i really like LISP, but still don't get through emacs. After i
learned a bit LISP i wanted to try it again, and again i failed ;) i
know vim from the in- and out- side and just feel completely lost in
emacs.

i also like vim with gtk2 support more. not because of menu or toolbar,
which are usually switched off in my config, but because of antialiased
letters. I just don't like coding with bleeding eyes anymore ;)

*to me* vim just looks and feels much more smooth than emacs, so i don't
think that hacking LISP influences the choice of the editor much. it of
course makes people *try* Emacs because of its LISP support.

Rene

gr...@cs.uwa.edu.au

unread,
Oct 6, 2003, 2:16:58 AM10/6/03
to
In comp.lang.functional Erann Gat <my-first-name...@jpl.nasa.gov> wrote:
:> I can't see why a LISP programmer would even want to write a macro.
: That's because you are approaching this with a fundamentally flawed
: assumption. Macros are mainly not used to make the syntax prettier
: (though they can be used for that). They are mainly used to add features
: to the language that cannot be added as functions.

Really? Turing-completeness and all that... I presume you mean "cannot
so easily be added as functions", but even that would surprise me.
(Unless you mean cannot be added _to_Lisp_ as functions, because I don't
know as much as I'd like to about Lisp's capabilities and limitations.)

: For example, imagine you want to be able to traverse a binary tree and do
: an operation on all of its leaves. In Lisp you can write a macro that
: lets you write:
: (doleaves (leaf tree) ...)
: You can't do that in Python (or any other langauge).

My Lisp isn't good enough to answer this question from your code,
but isn't that equivalent to the Haskell snippet: (I'm sure
someone here is handy in both languages)

doleaves f (Leaf x) = Leaf (f x)
doleaves f (Branch l r) = Branch (doleaves f l) (doleaves f r)

I'd be surprised if Python couldn't do the above, so maybe doleaves
is doing something more complex than it looks to me to be doing.

: Here's another example of what you can do with macros in Lisp:

: (with-collector collect
: (do-file-lines (l some-file-name)
: (if (some-property l) (collect l))))

: This returns a list of all the lines in a file that have some property.

OK, that's _definitely_ just a filter: filter someproperty somefilename
Perhaps throw in a fold if you are trying to abstract "collect".

: DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented
: any other way because they take variable names and code as arguments.

What does it mean to take a variable-name as an argument? How is that
different to taking a pointer? What does it mean to take "code" as an
argument? Is that different to taking a function as an argument?

-Greg

Marco Baringer

unread,
Oct 6, 2003, 3:22:03 AM10/6/03
to
gr...@cs.uwa.edu.au writes:

> Really? Turing-completeness and all that... I presume you mean "cannot
> so easily be added as functions", but even that would surprise me.

well you can pass around code full of lambdas so most macros (expect
the ones which perform hairy source transformations) can be rewritten
as functions, but that isn't the point. Macros are about saying what
you mean in terms that makes sense for your particular app.

> : Here's another example of what you can do with macros in Lisp:
>
> : (with-collector collect
> : (do-file-lines (l some-file-name)
> : (if (some-property l) (collect l))))
>
> : This returns a list of all the lines in a file that have some property.
>
> OK, that's _definitely_ just a filter: filter someproperty somefilename
> Perhaps throw in a fold if you are trying to abstract "collect".

no it's not, and the proof is that it wasn't written as a filter. For
whatever reason the author of that snippet decided that the code
should be written with WITH-COLLECTOR and not as a filter, some
languages give you this option, some don't, some people think this is
a good thing, some don't.

> : DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented
> : any other way because they take variable names and code as arguments.
>
> What does it mean to take a variable-name as an argument? How is that
> different to taking a pointer? What does it mean to take "code" as an
> argument? Is that different to taking a function as an argument?

You are confusing the times at which things happen. A macro is
expanded at compile time, there is no such thing as a pointer as far
as macros are concerned (more or less), macros are passed pieces of
source code in the form of lists and atoms and return _source code_ in
the form of lists and atoms. The source code is then compiled (whith
further macro expansion in need be) and finally, after the macro has
long since finished working, the code is executed.

Another trivial example:

We often see code like this:

(let ((var (foo)))
(if var
(do-stuff-with-var)
(do-other-stuff)))

So write a macro called IF-BIND which allows you to write this instead:

(if-bind var (foo)
(do-stuff-with-var)
(do-other-stuff))

The definition for IF-BIND is simply:

(defmacro if-bind (var condition then &optional else)
`(let ((,var ,condition))
(if ,then ,else)))

But what if the condition form returns multiple values which we didn't
want to throw away? Well easy enough:

(defmacro if-bind (var condition then &optional else)
(etypecase var
(cons `(multiple-value-bind ,var ,condition
(if ,(car var) ,then ,else)))
(symbol `(let ((,var ,condition))
(if ,var ,then ,else)))))

Notice how we use lisp to inspect the original code and decide what
code to produce depending on whether VAR is a cons or a symbol.

I could get the same effect (from an execution stand point) of if-bind
without the macro, but the source code is very different. Macros allow
me to say what I _mean_, not what the compiler wants.

If you want more examples look in Paul Graham's OnLisp
(http://www.paulgraham.com/onlisp.html) book for the chapters on
continuations or multitasking.

--
-Marco
Ring the bells that still can ring.
Forget your perfect offering.
There is a crack in everything.
That's how the light gets in.
-Leonard Cohen

Ingvar Mattsson

unread,
Oct 6, 2003, 5:29:45 AM10/6/03
to
Joe Marshall <j...@ccs.neu.edu> writes:

> Alexander Schmolck <a.sch...@gmx.net> writes:
>
> > prunes...@comcast.net writes:
> >
> >> mik...@ziplip.com writes:
> >>
> >> > I think everyone who used Python will agree that its syntax is
> >> > the best thing going for it.
> >>
> >> I've used Python. I don't agree.
> >
> > I'd be interested to hear your reasons. *If* you take the sharp distinction
> > that python draws between statements and expressions as a given, then python's
> > syntax, in particular the choice to use indentation for block structure, seems
> > to me to be the best choice among what's currently on offer (i.e. I'd claim
> > that python's syntax is objectively much better than that of the C and Pascal
> > descendants -- comparisons with smalltalk, prolog or lisp OTOH are an entirely
> > different matter).
>
> (I'm ignoring the followup-to because I don't read comp.lang.python)
>
> Indentation-based grouping introduces a context-sensitive element into
> the grammar at a very fundamental level. Although conceptually a
> block is indented relative to the containing block, the reality of the
> situation is that the lines in the file are indented relative to the
> left margin. So every line in a block doesn't encode just its depth
> relative to the immediately surrounding context, but its absolute
> depth relative to the global context. Additionally, each line encodes
> this information independently of the other lines that logically
> belong with it, and we all know that when some data is encoded in one
> place may be wrong, but it is never inconsistent.
>
> There is yet one more problem. The various levels of indentation
> encode different things: the first level might indicate that it is
> part of a function definition, the second that it is part of a FOR
> loop, etc. So on any line, the leading whitespace may indicate all
> sorts of context-relevant information. Yet the visual representation
> is not only identical between all of these, it cannot even be
> displayed.

It's actually even worse than you think. Imagine you want "blank
lines" in your code, so act as paragraph separators. Do these require
indentation, even though there is no code on them? If so, how does
that interact with a listener? From what I can tell, the option chosen
in the Python (the language) community, the listener and the file
reader have different view on blank lines. This makes it harder than
necessary to edit stuff in one window and "just paste" code from
another. Bit of a shame, really.

//ingvar
--
When it doesn't work, it's because you did something wrong.
Try to do it the right way, instead.

gr...@cs.uwa.edu.au

unread,
Oct 6, 2003, 6:19:46 AM10/6/03
to
In comp.lang.functional Marco Baringer <m...@bese.it> wrote:

: gr...@cs.uwa.edu.au writes:
:> Really? Turing-completeness and all that... I presume you mean "cannot
:> so easily be added as functions", but even that would surprise me.

: well you can pass around code full of lambdas so most macros (expect
: the ones which perform hairy source transformations) can be rewritten
: as functions, but that isn't the point. Macros are about saying what
: you mean in terms that makes sense for your particular app.

OK, so in some other application, they might allow you to extend the
syntax of the language to encode some problem domain more naturally?

:> OK, that's _definitely_ just a filter:
: no it's not, and the proof is that it wasn't written as a filter.

He was saying that this could not be done in Python, but Python has
a filter function, AFAIK.

: For whatever reason the author of that snippet decided that the code


: should be written with WITH-COLLECTOR and not as a filter, some
: languages give you this option, some don't, some people think this is
: a good thing, some don't.

Naturally. I'm against extra language features unless they increase
the expressive power, but others care more for ease-of-writing and
less for ease-of-reading and -maintaining than I do.

:> : DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented


:> : any other way because they take variable names and code as arguments.
:> What does it mean to take a variable-name as an argument? How is that
:> different to taking a pointer? What does it mean to take "code" as an
:> argument? Is that different to taking a function as an argument?
: You are confusing the times at which things happen. A macro is
: expanded at compile time,

OK, yep. It should have occurred to me that that was the difference.
So now the question is "what does that give you that higher-order
functions don't?".

: Another trivial example:
: <IF-BIND>

: Macros allow me to say what I _mean_, not what the compiler wants.

Interesting. It would be interesting to see an example where it allows
you to write the code in a less convoluted way, rather than the three
obfuscating (or would the non-macro Lisp versions be just as obfuscated?
I know Lisp is fine for higher-order functions, but I guess the IF-BIND
stuff might be hard without pattern-matching.) examples I've seen so far.

: If you want more examples look in Paul Graham's OnLisp


: (http://www.paulgraham.com/onlisp.html) book for the chapters on
: continuations or multitasking.

Doubtless I'll find good examples here, given the frequency I see
this site cited.

-Greg

Matthias

unread,
Oct 6, 2003, 6:54:30 AM10/6/03
to
gr...@cs.uwa.edu.au writes:

> In comp.lang.functional Erann Gat <my-first-name...@jpl.nasa.gov> wrote:
> :> I can't see why a LISP programmer would even want to write a macro.
> : That's because you are approaching this with a fundamentally flawed
> : assumption. Macros are mainly not used to make the syntax prettier
> : (though they can be used for that). They are mainly used to add features
> : to the language that cannot be added as functions.
>
> Really? Turing-completeness and all that... I presume you mean "cannot
> so easily be added as functions", but even that would surprise me.
> (Unless you mean cannot be added _to_Lisp_ as functions, because I don't
> know as much as I'd like to about Lisp's capabilities and limitations.)

IMHO, these discussions are less usefull when not accompanied by
specific examples. What are these macros good for? Some examples
where you might have difficulties with using ordinary functions:

1.) Inventing new control structures (implement lazy data structures,
implement declarative control structures, etc.)
=> This one is rarely needed in everyday application programming and
can easily be misused.

2.) Serve as abbreviation of repeating code. Ever used a code
generator? Discovered there was a bug in the generated code? Had
to fix it at a zillion places?
=> Macros serve as extremely flexible code generators, and there
is only one place to fix a bug.
=> Many Design Patterns can be implemented as macros, allowing you
to have them explicitly in your code. This makes for better
documentation and maintainability.

3.) Invent pleasant syntax in limited domains.
=> Some people don't like Lips' prefix syntax. It's changeable if you
have macros.
=> This feature can also be misused.

4.) Do computations at compile time instead of at runtime.
=> Have heard about template metaprogramming in the C++ world?
People do a lot to get fast performance by shifting computation
to compile time. Macros do this effortlessly.

These are four specific examples which are not easy to do without
macros. In all cases, implementing them classically will lead to code
duplication with all the known maintainability issues. In some cases
misuse will lead to unreadable or buggy code. Thus, macros are
powerful tools for the hand of professionals. You have to know if you
want a sharp knife (which may hurt you when misused) or a less sharper
one (where it takes more effort to cut with).

Pascal Bourguignon

unread,
Oct 6, 2003, 7:05:10 AM10/6/03
to
gr...@cs.uwa.edu.au writes:
> What does it mean to take a variable-name as an argument? How is that
> different to taking a pointer? What does it mean to take "code" as an
> argument? Is that different to taking a function as an argument?

The difference is that you can declare (compilation-time) it and
associated variables or functions.

For example, I recently defined this macro, to declare at the same
time a class and a structure, and to define a couple of methods to
copy the objects to and from structures.

That's so useful that even cpp provide us with a ## operator to build
new symbols.

(DEFMACRO DEFCLASS-AND-STRUCT (NAME SUPER-CLASSES ATTRIBUTES OPTIONS)
(LET ((STRUCT-NAME (INTERN (FORMAT NIL "~A-STRUCT" NAME))))
`(PROG1
(DEFCLASS ,NAME ,SUPER-CLASSES ,ATTRIBUTES ,OPTIONS)
(DEFSTRUCT ,STRUCT-NAME
,@(MAPCAR (LAMBDA (ATTRIBUTE)
(CONS
(CAR ATTRIBUTE)
(CONS (GETF (CDR ATTRIBUTE) :INITFORM NIL)
(IF (GETF (CDR ATTRIBUTE) :TYPE NIL)
NIL
(LIST :TYPE (GETF (CDR ATTRIBUTE) :TYPE))))))
ATTRIBUTES))
(DEFMETHOD COPY-TO-STRUCT ((SELF ,NAME))
(MAKE-STRUCT
',NAME
,@(MAPCAN (LAMBDA (ATTRIBUTE)
`(,(INTERN (STRING (CAR ATTRIBUTE)) "KEYWORD")
(COPY-TO-STRUCT (SLOT-VALUE SELF ',(CAR ATTRIBUTE)))))
ATTRIBUTES)))
(DEFMETHOD COPY-FROM-STRUCT ((SELF ,NAME) (STRUCT ,STRUCT-NAME))
,@(MAPCAR
(LAMBDA (ATTRIBUTE)
`(SETF (SLOT-VALUE SELF ',(CAR ATTRIBUTE))
(,(INTERN (FORMAT NIL "~A-~A"
STRUCT-NAME (CAR ATTRIBUTE))) STRUCT)))
ATTRIBUTES)
SELF)
))
);;DEFCLASS-AND-STRUCT


--
__Pascal_Bourguignon__
http://www.informatimago.com/
Do not adjust your mind, there is a fault in reality.

Raymond Wiker

unread,
Oct 6, 2003, 7:09:00 AM10/6/03
to
Matthias <n...@spam.pls> writes:

> 1.) Inventing new control structures (implement lazy data structures,
> implement declarative control structures, etc.)
> => This one is rarely needed in everyday application programming and
> can easily be misused.

This is, IMHO, wrong. One particular example is creating
macros (or read macros) for giving values to application-specific data
structures.

> You have to know if you want a sharp knife (which may hurt you when
> misused) or a less sharper one (where it takes more effort to cut
> with).

It is easier to hurt yourself with a blunt knife than a sharp
one.

--
Raymond Wiker Mail: Raymon...@fast.no
Senior Software Engineer Web: http://www.fast.no/
Fast Search & Transfer ASA Phone: +47 23 01 11 60
P.O. Box 1677 Vika Fax: +47 35 54 87 99
NO-0120 Oslo, NORWAY Mob: +47 48 01 11 60

Try FAST Search: http://alltheweb.com/

David Rush

unread,
Oct 6, 2003, 6:17:52 AM10/6/03
to
On Sat, 04 Oct 2003 16:48:00 GMT, <prunes...@comcast.net> wrote:
> I agree that injudicious use of macros can destroy the readability of
> code, but judicious use can greatly increase the readability. So
> while it is probably a bad idea to write COND1 that assumes
> alternating test and consequence forms, it is also a bad idea to
> replicate boilerplate code because you are eschewing macros.

But it may also be a mistake to use macros for the boilerplate code when
what you really need is a higher-order function...

Joe Marshall

unread,
Oct 6, 2003, 10:09:11 AM10/6/03
to
David Rush <dr...@aol.net> writes:

> On Sat, 04 Oct 2003 16:48:00 GMT, <prunes...@comcast.net> wrote:
>> I agree that injudicious use of macros can destroy the readability of
>> code, but judicious use can greatly increase the readability. So
>> while it is probably a bad idea to write COND1 that assumes
>> alternating test and consequence forms, it is also a bad idea to
>> replicate boilerplate code because you are eschewing macros.
>
> But it may also be a mistake to use macros for the boilerplate code when
> what you really need is a higher-order function...

Certainly.

One should be willing to use the appropriate tools: higher-order
functions, syntactic abstraction, and meta-linguistic abstraction
(embedding a domain-specific `tiny language' within the host
language). Macros come in handy for the latter two.

Neelakantan Krishnaswami

unread,
Oct 6, 2003, 10:29:27 AM10/6/03
to
In article <blr1cq$bb1$1...@enyo.uwa.edu.au>, gr...@cs.uwa.edu.au wrote:
> In comp.lang.functional Erann Gat <my-first-name...@jpl.nasa.gov>
> wrote:
>:> I can't see why a LISP programmer would even want to write a macro.
>: That's because you are approaching this with a fundamentally flawed
>: assumption. Macros are mainly not used to make the syntax prettier
>: (though they can be used for that). They are mainly used to add features
>: to the language that cannot be added as functions.
>
> Really? Turing-completeness and all that... I presume you mean
> "cannot so easily be added as functions", but even that would
> surprise me. (Unless you mean cannot be added _to_Lisp_ as
> functions, because I don't know as much as I'd like to about Lisp's
> capabilities and limitations.)

You know Haskell. Think about the do-noatation for monads: it takes
what would be awkward, error-prone code (using >> and >>= manually)
and makes it pleasant and readable. Do-notation is basically a macro
(and can easily be expressed as such in Scheme or Lisp). Syntactic
convenience is very important; consider how many fewer programmers in
ML are willing to reach for a monadic solution, even when it would be
appropriate. Or for that matter, think how many fewer Java programmers
are willing to write a fold than in ML or Haskell, even when it would
be appropriate.


--
Neel Krishnaswami
ne...@cs.cmu.edu

Matthew Danish

unread,
Oct 6, 2003, 10:51:10 AM10/6/03
to
On Mon, Oct 06, 2003 at 10:19:46AM +0000, gr...@cs.uwa.edu.au wrote:
> In comp.lang.functional Marco Baringer <m...@bese.it> wrote:
> : gr...@cs.uwa.edu.au writes:
> :> Really? Turing-completeness and all that... I presume you mean "cannot
> :> so easily be added as functions", but even that would surprise me.
>
> : well you can pass around code full of lambdas so most macros (expect
> : the ones which perform hairy source transformations) can be rewritten
> : as functions, but that isn't the point. Macros are about saying what
> : you mean in terms that makes sense for your particular app.
>
> OK, so in some other application, they might allow you to extend the
> syntax of the language to encode some problem domain more naturally?

Right.

>
> :> OK, that's _definitely_ just a filter:
> : no it's not, and the proof is that it wasn't written as a filter.
>
> He was saying that this could not be done in Python, but Python has
> a filter function, AFAIK.

He meant the way it was expressed. Java can ``do'' it too, but it's not
going to look as simple.

>
> : For whatever reason the author of that snippet decided that the code
> : should be written with WITH-COLLECTOR and not as a filter, some
> : languages give you this option, some don't, some people think this is
> : a good thing, some don't.
>
> Naturally. I'm against extra language features unless they increase
> the expressive power, but others care more for ease-of-writing and
> less for ease-of-reading and -maintaining than I do.

Then you should like macros, because ease-of-reading and -maintaining is
precisely why I use them. Like with functions, being able to label
common abstractions is a great maintainability boost.

You don't write ((lambda (x) ...) 1) instead of (let ((x 1)) ...), right?

> :> : DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented
> :> : any other way because they take variable names and code as arguments.
> :> What does it mean to take a variable-name as an argument? How is that
> :> different to taking a pointer? What does it mean to take "code" as an
> :> argument? Is that different to taking a function as an argument?
> : You are confusing the times at which things happen. A macro is
> : expanded at compile time,
>
> OK, yep. It should have occurred to me that that was the difference.
> So now the question is "what does that give you that higher-order
> functions don't?".
> : Another trivial example:
> : <IF-BIND>
>
> : Macros allow me to say what I _mean_, not what the compiler wants.
>
> Interesting. It would be interesting to see an example where it allows
> you to write the code in a less convoluted way, rather than the three
> obfuscating (or would the non-macro Lisp versions be just as obfuscated?
> I know Lisp is fine for higher-order functions, but I guess the IF-BIND
> stuff might be hard without pattern-matching.) examples I've seen so far.

Here's an example that I am currently using:

(definstruction move ((s register) (d register))
:sources (s)
:destinations (d)
:template "movl `s0, `d0"
:class-name move-instruction)

1. This expands into a
(defmethod make-instruction-move ((s register) (d register)) ...)
which itself is called indirectly, but most importantly it allows the
compiler to compile a multiple-dispatch method statically rather than
trying to replicate that functionality at runtime (which would require
parsing a list of parameters supplied by the &rest lambda-list keyword,
not to mention implementing multiple-dispatch).

2. Sources and destinations can talk about variable names rather than indices
into a sequence. (Templates cannot because they need the extra layer of
indirection--the source and destination lists are subject to change in
this system currently. Well, I suppose it could be worked out anyway,
perhaps if I have time I will try it).

3. Originally I processed the templates at run-time, and upon profiling
discovered that it was the most time-consuming function by far. I modified
the macro to process the template strings statically and produce a
function which could be compiled with the rest of the code, and the
overhead completely disappeared. I can imagine a way to do this with
functions: collect a list of functions which take the relevant values
as arguments, then map over them and apply the results to format.
This is less efficient because
(a) you need to do some extra steps, which the macro side-steps by
directly pasting the code into the proper place, and
(b) FORMATTER is a macro which lets you compile a format string into
a function, and this cannot be used in the functional version,
since you cannot say (FORMATTER my-control-string) but must supply
a string statically, as in (FORMATTER "my control string").
Could FORMATTER be implemented functionally? Probably, but either
you require the use of the Lisp compiler at run-time, which is
certainly possible though heavyweight usually, or you write a
custom compiler for that function. If you haven't figured it out
yet, Lispers like to leverage existing resources =)

4. The macro arranges all the relevant information about a machine instruction
in a simple way that is easy to write even if you don't understand
the underlying system. If you know anything about assembly language,
it is probably pretty easy to figure out what information is being encoded.


Here's another fun macro which I've been using as of yesterday afternoon,
courtesy of Faré Rideau:

(match s
...
((ir move (as temp (ir temp _)) b)
(reorder-stm (list b)
(mlambda ((list b) ;; match + lambda
(make-ir-move temp b)))))
...)

MATCH performs ML/Erlang-style pattern matching with a Lispy twist: patterns
are of the form: literal, variable, or (designator ...) where designator is a
symbol specified by some defining construct.

I wrote this to act like the ML `as' [meta-?]pattern:

(define-macro-matcher as
;; I think this lambda should be folded into the macro, but whatever
#'(lambda (var pat)
(multiple-value-bind (matcher vars)
(pattern-matcher pat)
(values `#'(lambda (form)
(m%and (funcall ,matcher form)
(setf ,var form)))
(merge-matcher-variables (list vars (list var)))))))

for example, which at macro-expansion time computes the pattern-matching code
of the pat argument, adds var to the list of variables (used by MATCH), and
creates a function which first checks the pattern and then sets the supplied
(lexical) variable var to the value of the form at this point the form at this
point. Calling PATTERN-MATCHER yourself is quite enlightening on this:

* (pattern-matcher '(as x 1))
#'(LAMBDA (FORM)
(M%AND (FUNCALL #'(LAMBDA (#:FORM) (M%WHEN (EQL #:FORM '1))) FORM)
(SETF X FORM)))
(X)

MATCH (really implemented in terms of IFMATCH) computes this at macro-expansion
and the Lisp statically compiles it afterwards. Of course, MATCH could be
implemented functionally, but consider the IR matcher that
(a) looks up the first parameter in a table (created by another macro) to
see if it is a valid IR type and get the slot names
(b) which are used to create slot-accessing forms that can be optimized
by a decent CLOS implementation when the slot-name is a literal value
(as when constructed by the macro, something a functional version
could not do).

Not to mention that a functional version would have to look something like:

(match value
'(pattern involving x, y, and z) #'(lambda (x y z) ...)
... ...)

Rather annoying, don't you think? The variables need to be repeated.

The functional version would have to create some kind of structure to hold the
bound variable values and construct a list to apply the consequent function
with. The macro version can get away with modifying lexical variables.

Also the macro version can be extended to support multiple value forms, which
in Lisp are not first-class (but more efficient than returning lists).


A third quick example:

(ir-sequence
(make-ir-move ...)
(make-ir-jump ...)
...)

Which transforms a list of values into a list-like data structure. I wrote
this originally as a macro, because in my mind it was a static transformation.
I realized later that it could be implemented as a function, without changing
any uses, but I didn't because
(a) I wasn't using it with higher-order functions, or situations demanding
them.
(b) It would now have to cons a list every call and do the transformation;
added overhead and the only gain being that it was now a function which
I never even used in a functional way. Rather questionable.
(c) I can always write a separate functional version if I need it.


Basically, this boils down to:

* Macros can do ``compile-time meta-programming'' or whatever the buzzword
is these days, and those above are some real-life examples.
This allows for compiler optimization and static analysis where desired.
* Macros make syntax much more convenient and less cluttered. I really
don't understand the people who think that macros make things harder to read.
It is far better to have clear labelled markers in the source code rather
than having to sort through boilerplate to figure out the intended meaning
of code. Just because I understand lambda calculus doesn't mean I want to
sort through nested lambdas just to use some functionality, every time.
If you are afraid because you are unsure of what the macro does, or its
complete syntax, MACROEXPAND-1 is your friend. That, and an editor with
some hot-keys to find source/docs/expansion/etc.

--
; Matthew Danish <mda...@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."

Raymond Wiker

unread,
Oct 6, 2003, 11:36:52 AM10/6/03
to
Another example:

Given a set of files containing database data, I want to create

- classes that represent (the interesting bits of) each table

- functions that parse lines from the files, create instances
of a given class, and returns the instance along with the "primary
key" of the instance.

The interface to this functionality is the macro

(defmacro define-record (name key args &body body)
...)

which I use like this:

(define-record category oid ((oid 0 integer)
(name 1 string)
(status 4 integer)
(deleted 5 integer)
(parent 9 integer)
active)
(unless (zerop deleted)
(return t)))

which expands into

(PROGN
(DEFCLASS CATEGORY-CLASS
NIL
((OID :INITARG :OID) (NAME :INITARG :NAME) (STATUS :INITARG :STATUS)
(DELETED :INITARG :DELETED) (PARENT :INITARG :PARENT)
(ACTIVE :INITARG :ACTIVE)))
(DEFUN HANDLE-CATEGORY (#:LINE-2524)
(WHEN #:LINE-2524
(LET ((#:FIELDS-2525
(SPLIT-LINE-COLLECT #:LINE-2524
'((0 . INTEGER) (1 . STRING) (4 . INTEGER)
(5 . INTEGER) (9 . INTEGER)))))
(WHEN #:FIELDS-2525
(PROGV
'(OID NAME STATUS DELETED PARENT)
#:FIELDS-2525
(BLOCK NIL
(LET (ACTIVE)
(UNLESS (ZEROP DELETED) (RETURN T))
(VALUES OID
(MAKE-INSTANCE 'CATEGORY-CLASS
:OID
OID
:NAME
NAME
:STATUS
STATUS
:DELETED
DELETED
:PARENT
PARENT
:ACTIVE
ACTIVE))))))))))

The implementation of this macro is probably not perfect (I've
learnt more about Common Lisp since I wrote it). This is OK, since I
can go back and change the innards of the macro whenever I want to :-)
Actually, this is probably something that calls for the use of MOP.

Peter Seibel

unread,
Oct 6, 2003, 12:17:35 PM10/6/03
to
gr...@cs.uwa.edu.au writes:

> In comp.lang.functional Marco Baringer <m...@bese.it> wrote:

[snip]

> : You are confusing the times at which things happen. A macro is
> : expanded at compile time,
>
> OK, yep. It should have occurred to me that that was the difference.
> So now the question is "what does that give you that higher-order
> functions don't?".

Clean syntax. That is, clean syntax that allows your code to
express--in terms of the problem at hand--what it is doing, hiding the
actual mechanics under the macro. See my example below.

> : Macros allow me to say what I _mean_, not what the compiler wants.
>
> Interesting. It would be interesting to see an example where it allows
> you to write the code in a less convoluted way, rather than the three
> obfuscating (or would the non-macro Lisp versions be just as obfuscated?
> I know Lisp is fine for higher-order functions, but I guess the IF-BIND
> stuff might be hard without pattern-matching.) examples I've seen so far.

Okay, here's an example of a couple macros I use all the time. Since I
write a lot of unit tests, I like to have a clean syntax for
expressing the essence of a set of related tests. So I have a macro
DEFTEST which is similar to DEFUN except it defines a "test function"
which has some special characteristics. For one, all test functions
are registered with the test framework so I can run all defined tests.
And each test function binds a dynamic variable to the name of the
test currently being run which is used by the reporting framework when
reporting results. So, to write a new test function, here's what I
write:

(deftest foo-tests ()
(check
(= (foo 1 2 3) 42)
(= (foo 4 5 6) 99)))

Note that this is all about the problem domain, namely testing. Each
form within the body of the CHECK is evaluated as a separate test
case. If a given form doesn't evaluate to true then a failure is
reported like this which tells me which test function the failure was
in, the literal form of the test case and then the values of any
non-literal values is the function call (i.e. the arguments to = in
this case.)

Test Failure:

Test Name: (FOO-TESTS)
Test Case: (= (FOO 1 2 3) 42)
Values: (FOO 1 2 3): 6


Test Failure:

Test Name: (FOO-TESTS)
Test Case: (= (FOO 4 5 6) 99)
Values: (FOO 4 5 6): 15


So what is the equivalent non-macro code? Well the equivalent code to
the DEFTEST form (i.e. the macro expansion) is not *that* much more
complex--it just has to do the stuff I mentioned; binding the test
name variable and registering the test function. But it's complex
enough that I sure wouldn't want to have to type it over and over
again each time I write a test:

(progn
(defun foo-tests ()
(let ((test::*test-name*
(append test::*test-name* (list 'foo-tests))))
(check
(= (foo 1 2 3) 42)
(= (foo 4 5 6) 99))))
(eval-when (:compile-toplevel :load-toplevel :execute)
(test::add-test 'foo-tests)))

But the real payoff comes when we realize that innocent looking CHECK
is also a macro. Thus to see what the *real* benefit of macros is we
need to compare the original four-line DEFTEST form to what it expands
into (i.e. what the compiler actually compiles) when all the
subsidiary macros are also expanded. Which is this:

(progn
(defun foo-tests ()
(let ((test::*test-name*
(append test::*test-name* (list 'foo-tests))))
(let ((#:end-result356179 t))
(tagbody
test::retry
(multiple-value-bind (#:result356180 #:bindings356181)
(let ((#:g356240 (foo 1 2 3)) (#:g356241 42))
(values (= #:g356240 #:g356241)
(list (list '(foo 1 2 3) #:g356240))))
(if #:result356180
(signal
'test::test-passed
:test-name test::*test-name*
:test-case '(= (foo 1 2 3) 42)
:bound-values #:bindings356181)
(restart-case
(signal
'test::test-failed
:test-name test::*test-name*
:test-case '(= (foo 1 2 3) 42)
:bound-values #:bindings356181)
(test::skip-test-case nil)
(test::retry-test-case nil (go test::retry))))
(setq #:end-result356179
(and #:end-result356179 #:result356180))))
(tagbody
test::retry
(multiple-value-bind (#:result356180 #:bindings356181)
(let ((#:g356242 (foo 4 5 6)) (#:g356243 99))
(values (= #:g356242 #:g356243)
(list (list '(foo 4 5 6) #:g356242))))
(if #:result356180
(signal
'test::test-passed
:test-name test::*test-name*
:test-case '(= (foo 4 5 6) 99)
:bound-values #:bindings356181)
(restart-case
(signal
'test::test-failed
:test-name test::*test-name*
:test-case '(= (foo 4 5 6) 99)
:bound-values #:bindings356181)
(test::skip-test-case nil)
(test::retry-test-case nil (go test::retry))))
(setq #:end-result356179
(and #:end-result356179 #:result356180))))
#:end-result356179)))
(eval-when (:compile-toplevel :load-toplevel :execute)
(test::add-test 'foo-tests)))


Note that it's the ability, at macro expansion time, to treat the code
as data that allows me to generate test failure messages that contain
the literal code of the test case *and* the value that it evaluated
to. I could certainly write a HOF version of CHECK that accepts a list
of test-case-functions:

(defun check (test-cases)
(dolist (case test-cases)
(if (funcall case)
(report-pass case)
(report-failure case))))

which might be used like:

(defun foo-tests ()
(check
(list
#'(lambda () (= (foo 1 2 3) 42))
#'(lambda () (= (foo 4 5 6) 99)))))


But since each test case would be an opaque function object by the
time CHECK sees it, there'd be no good option for nice reporting from
the test framework. (Of course I'm no functional programming wizard so
maybe there are other ways to do it in other languges (or even Lisp)
but for me, the test, no pun intended, is, is the thing I have to
write to define a new test function much more complex than my original
DEFTEST form?

-Peter

--
Peter Seibel pe...@javamonkey.com

Lisp is the red pill. -- John Fraser, comp.lang.lisp

Marco Baringer

unread,
Oct 6, 2003, 12:52:03 PM10/6/03
to

[just to be clear: when i say "lisp" i mean Common Lisp, when I talk
about macros I'm talking about Common Lisp's macros]

gr...@cs.uwa.edu.au writes:

> : well you can pass around code full of lambdas so most macros (expect
> : the ones which perform hairy source transformations) can be rewritten
> : as functions, but that isn't the point. Macros are about saying what
> : you mean in terms that makes sense for your particular app.
>
> OK, so in some other application, they might allow you to extend the
> syntax of the language to encode some problem domain more naturally?

exactly. I'd just change the wording to make it a bit stronger:

[macros used properly] in applications allow you to extend the syntax
of the [underlying] language to encode your problem domain naturally.

> :> OK, that's _definitely_ just a filter:
> : no it's not, and the proof is that it wasn't written as a filter.
>
> He was saying that this could not be done in Python, but Python has
> a filter function, AFAIK.

so does common lisp (it's called remove-if-not), that's not the point
I was trying to make though.

What I was trying to say is that the author, having the option to
write his code via a filter or via a block of code with calls to a
collector function chose the later, in python you don't have this
option. In python you can _not_ define new control structures, you are
limited to the one's Mr. van Rossum has decided to include. The fact
that you _can_ write code using only lambda means nothing; I _could_
program in unlambda, but I don't plan on it.

This brings up another point I'd like to make: If you have macros
anyone can try new control structs and see how they work in real
code, only when a lot people use it in a lot of code do you
standardive it. Without macros you have to first allow a small group
of people decide how the structure should work and then you see how
it works "in the wild."

> : For whatever reason the author of that snippet decided that the code
> : should be written with WITH-COLLECTOR and not as a filter, some
> : languages give you this option, some don't, some people think this is
> : a good thing, some don't.
>
> Naturally. I'm against extra language features unless they increase
> the expressive power, but others care more for ease-of-writing and
> less for ease-of-reading and -maintaining than I do.

but it's not that clear cut. You can't simply prefer one over the
other, they go hand in hand. You have to decide how much you're
willing to sacrifice in one for the other. Every language feature
increases experssive power, everything that eases writing increase in
some way the difficulty of reading/maintaining, but how much weight do
you give to each arm of the scale? Do you have a meter for this? (I
don't think one exists)

Let me ask a few questions:

1) Are you willing to gain writability at the cast of having the
readers to learn a new word? How many pages of documentation would
you sacrifice in order to save 5 "boiler plate" statements in 20
places in your code? 1? 0.5?

2) Would you add an "official" language feature to consolidate an
idiom that has been around for 5 years? if it has been around for
20 years?

2b) If your main customer has been using an idiom for 10 years would
you ever consider modifying the language to consolidate that idiom
in the language? If no, why?

3) Do you think that being able to mold the language to fit your
problem is a good thing?

3b) Is this so good that it's worth the added effort of learning a new
language feature?

> OK, yep. It should have occurred to me that that was the difference.
> So now the question is "what does that give you that higher-order
> functions don't?".

introspection.

> Interesting. It would be interesting to see an example where it allows
> you to write the code in a less convoluted way, rather than the three
> obfuscating (or would the non-macro Lisp versions be just as obfuscated?

was the code I posted obfuscated?

> I know Lisp is fine for higher-order functions, but I guess the IF-BIND
> stuff might be hard without pattern-matching.) examples I've seen so far.

(can you write a drop-in replacement for if-bind using pattern matching?)

With no documentation, no idea of what the rest of the framework does,
no idea of what app this is in, can you guess what this does?

(defaction purchase-order
(with-session-transaction
(unless (session.user *session*)
(call 'login :message "You must be logged in to complete your purchase"))
(let ((order (current-order *session*)))
(when (order.products order)
(call 'shipping-info :order order)))
(dolist (service (order.services order))
(setf (signup-infos service) (call 'sigup-info :service service)))
(case (call 'payment-methods :order order
:allowed-methods (valid-payment-methods order))
(:credit-card (call 'get-credit-card-info :order order))
(:finance (if (user.financing user)
(call 'finance-handler :order order)
(progn
(call 'bad-financing-info)
(goto 'shopping-cart)))))
(when (call 'confirm-order :order order)
(if (close-out-order order)
(call 'order-summary :order order)
(call 'order-closing-error :order order))))
(goto 'home-page))

It's the order purchasing page flow logic for an e-commerce site.
This single block of code controls a possibly infinite number of http
request/response interactions (at least 3) (and the evil back button),
yet reads like a linear sequence of function calls. I _could_ have
written the continuation passing style code which this block expands
to (all 200+ lines of it), but I wouldn't (trust me, I have tried).

I have written this exact same code in various languages and
frameworks (servlet/ASP/mod_perl) and this is _by far_ the
clearest.

Erann Gat

unread,
Oct 6, 2003, 12:55:09 PM10/6/03
to
In article <blr1cq$bb1$1...@enyo.uwa.edu.au>, gr...@cs.uwa.edu.au wrote:

> In comp.lang.functional Erann Gat
<my-first-name...@jpl.nasa.gov> wrote:
> :> I can't see why a LISP programmer would even want to write a macro.
> : That's because you are approaching this with a fundamentally flawed
> : assumption. Macros are mainly not used to make the syntax prettier
> : (though they can be used for that). They are mainly used to add features
> : to the language that cannot be added as functions.
>
> Really? Turing-completeness and all that... I presume you mean "cannot
> so easily be added as functions", but even that would surprise me.

No, I meant what I wrote. Turing-completeness is a red herring with
respect to a discussion of programming language features. If it were not
then there would be no reason to program in anything other than machine
language.


> : For example, imagine you want to be able to traverse a binary tree and do
> : an operation on all of its leaves. In Lisp you can write a macro that
> : lets you write:
> : (doleaves (leaf tree) ...)
> : You can't do that in Python (or any other langauge).
>
> My Lisp isn't good enough to answer this question from your code,
> but isn't that equivalent to the Haskell snippet: (I'm sure
> someone here is handy in both languages)
>
> doleaves f (Leaf x) = Leaf (f x)
> doleaves f (Branch l r) = Branch (doleaves f l) (doleaves f r)
>
> I'd be surprised if Python couldn't do the above, so maybe doleaves
> is doing something more complex than it looks to me to be doing.

You need to change your mode of thinking. It is not that other languages
cannot do what doleaves does. It is that other langauges cannot do what
doleaves does in the way that doleaves does it, specifically allowing you
to put the code of the body in-line rather than forcing you to construct a
function.

Keep in mind also that this is just a trivial example. More sophisticated
examples don't fit well in newsgroup postings. Come see my ILC talk for
an example of what you can do with macros in Lisp that you will find more
convincing.

> : Here's another example of what you can do with macros in Lisp:
>
> : (with-collector collect
> : (do-file-lines (l some-file-name)
> : (if (some-property l) (collect l))))
>
> : This returns a list of all the lines in a file that have some property.
>
> OK, that's _definitely_ just a filter: filter someproperty somefilename
> Perhaps throw in a fold if you are trying to abstract "collect".

The net effect is a filter, but again, you need to stop thinking about the
"what" and start thinking about the "how", otherwise, as I said, there's
no reason to use anything other than machine language.

> : DO-FILE-LINES and WITH-COLLECTOR are macros, and they can't be implemented
> : any other way because they take variable names and code as arguments.
>
> What does it mean to take a variable-name as an argument? How is that
> different to taking a pointer? What does it mean to take "code" as an
> argument? Is that different to taking a function as an argument?

These questions are answered in various books. Go seek them out and read
them. Paul Graham's "On Lisp" is a good place to start.

E.

David Eppstein

unread,
Oct 6, 2003, 1:46:13 PM10/6/03
to
In article
<my-first-name.my-last...@k-137-79-50-101.jpl.nasa.go
v>,
my-first-name...@jpl.nasa.gov (Erann Gat) wrote:

> > : Here's another example of what you can do with macros in Lisp:
> >
> > : (with-collector collect
> > : (do-file-lines (l some-file-name)
> > : (if (some-property l) (collect l))))
> >
> > : This returns a list of all the lines in a file that have some property.
> >
> > OK, that's _definitely_ just a filter: filter someproperty somefilename
> > Perhaps throw in a fold if you are trying to abstract "collect".
>
> The net effect is a filter, but again, you need to stop thinking about the
> "what" and start thinking about the "how", otherwise, as I said, there's
> no reason to use anything other than machine language.

Answer 1: literal translation into Python. The closest analogue of
with-collector etc would be Python's simple generators (yield keyword)
and do-with-file-lines is expressed in python with a for loop. So:

def lines_with_some_property(some_file_name):
for l in some_file_name:
if some_property(l):
yield l

Your only use of macros in this example is to handle the with-collector
syntax, which is handled in a clean macro-free way by Python's "yield".
So this is unconvincing as a demonstration of why macros are a necessary
part of a good programming language.

Of course, with-collector could be embedded in a larger piece of code,
while using yield forces lines_with_some_property to be a separate
function, but modularity is good...

Answer 2: poetic translation into Python. If I think about "how" I want
to express this sort of filtering, I end up with something much less
like the imperative-style code above and much more like:

[l for l in some_file_name if some_property(l)]

I have no problem with the assertion that macros are an important part
of Lisp, but you seem to be arguing more generally that the lack of
macros makes other languages like Python inferior because the literal
translations of certain macro-based code are impossible or more
cumbersome. For the present example, even that argument fails, but more
generally you'll have to also convince me that even a freer poetic
translation doesn't work.

Marco Antoniotti

unread,
Oct 6, 2003, 2:20:13 PM10/6/03
to

Sander Vesik wrote:
> In comp.lang.scheme David Rush <dr...@aol.net> wrote:
>
>>>Exceptions no yes
>>
>> yes, via continuations which reify the
>> fundamental control operators in all languages
>
>
> the exceptions SRFI and saying it is there as an extension would imho be a
> better answer.


It would also be more correct to point out that most of the SRFI's
address features that are already in the CL standard and reliably
implemented in all CL implementations (which are at least 9).


>
>
>>>Implementations >10 ~4
>>
>> too many to count. The FAQ lists over twenty. IMO
>> there are about 9 'major' implementations which
>>have
>> relatively complete compliance to R5RS and/or
>> significant extension libraries
>>
>
>
> And the number is likely to continue increase over the years. Scheme is
> very easy to implement, including as an extensions language inside the
> runtime of something else. The same doesn't really hold for common lisp.

One of the reasons why all the time spent on the godzillionth
incompatible Scheme implementation would be better spent on improving
Common Lisp.

Cheers
--
Marco Antoniotti

David Rush

unread,
Oct 6, 2003, 2:51:20 PM10/6/03
to
On Mon, 06 Oct 2003, Raymond Wiker <Raymon...@fast.no> wrote:
> Matthias <n...@spam.pls> writes:
>> (In certain cases macros) can easily be misused.
...

>> You have to know if you want a sharp knife (which may hurt you when
>> misused) or a less sharper one (where it takes more effort to cut
>> with).
>
> It is easier to hurt yourself with a blunt knife than a sharp
> one.

Actually I've noticed that I usually cut myself when I *switch* from
a dull knife to a sharp one.

Erann Gat

unread,
Oct 6, 2003, 3:19:54 PM10/6/03
to
In article <eppstein-9700A3...@news.service.uci.edu>, David
Eppstein <epps...@ics.uci.edu> wrote:

> In article
> <my-first-name.my-last...@k-137-79-50-101.jpl.nasa.go
> v>,
> my-first-name...@jpl.nasa.gov (Erann Gat) wrote:
>
> > > : Here's another example of what you can do with macros in Lisp:
> > >
> > > : (with-collector collect
> > > : (do-file-lines (l some-file-name)
> > > : (if (some-property l) (collect l))))
> > >
> > > : This returns a list of all the lines in a file that have some property.
> > >
> > > OK, that's _definitely_ just a filter: filter someproperty somefilename
> > > Perhaps throw in a fold if you are trying to abstract "collect".
> >
> > The net effect is a filter, but again, you need to stop thinking about the
> > "what" and start thinking about the "how", otherwise, as I said, there's
> > no reason to use anything other than machine language.
>
> Answer 1: literal translation into Python. The closest analogue of
> with-collector etc would be Python's simple generators (yield keyword)
> and do-with-file-lines is expressed in python with a for loop. So:
>
> def lines_with_some_property(some_file_name):
> for l in some_file_name:
> if some_property(l):
> yield l

You left out the with-collector part.

But it's true that my examples are less convincing given the existence of
yield (which I had forgotten about). But the point is that in pre-yield
Python you were stuck until the langauge designers got around to adding
it.

I'll try to come up with a more convincing short example if I find some
free time today.

E.

Joe Marshall

unread,
Oct 6, 2003, 4:56:17 PM10/6/03
to
David Rush <dr...@aol.net> writes:

> On Mon, 06 Oct 2003, Raymond Wiker <Raymon...@fast.no> wrote:
>> Matthias <n...@spam.pls> writes:
>>> (In certain cases macros) can easily be misused.
> ...
>>> You have to know if you want a sharp knife (which may hurt you when
>>> misused) or a less sharper one (where it takes more effort to cut
>>> with).
>>
>> It is easier to hurt yourself with a blunt knife than a sharp
>> one.
>
> Actually I've noticed that I usually cut myself when I *switch* from
> a dull knife to a sharp one.

Grasp the sharp knife by the *handle* when switching.

Raffael Cavallaro

unread,
Oct 6, 2003, 6:05:30 PM10/6/03
to
gr...@cs.uwa.edu.au wrote in message news:<blr1cq$bb1$1...@enyo.uwa.edu.au>...

> In comp.lang.functional Erann Gat <my-first-name...@jpl.nasa.gov> wrote:
> :> I can't see why a LISP programmer would even want to write a macro.
> : That's because you are approaching this with a fundamentally flawed
> : assumption. Macros are mainly not used to make the syntax prettier
> : (though they can be used for that). They are mainly used to add features
> : to the language that cannot be added as functions.
>
> Really? Turing-completeness and all that... I presume you mean "cannot
> so easily be added as functions", but even that would surprise me.
> (Unless you mean cannot be added _to_Lisp_ as functions, because I don't
> know as much as I'd like to about Lisp's capabilities and limitations.)

Two words: code duplication.

Yes, anything that can be done with macros can also be done with
functions, but if you do it with functions, you will end up with more
code, and that code will be duplicated in every single source location
in which that abstraction it utilized.

With a macro, the abstraction is defined once, and the source code
reflects that abstraction everywhere that abstraction is used
throughout your program. For large projects this could be hundreds of
source locations.

Without a macro, you have multiple points of maintenance. If your
abstraction changes, you have to edit scores or hundreds of source
locations. With a macro, you redefine a single form, in one source
location, and recompile the dependent code.

All turing complete languages are computationally equivalent. That
doesn't mean you'll see me programming by punching holes in a paper
tape any time soon though.

Finally, there is one thing that macros can do that ordinary functions
cannot do easily - change the language's rules for functional
evaluation. This can only be accomplished with functions if you're
willing to write a set of functions that defer evaluation, by, say
parsing input, massaging it appropriately, and then passing it to the
compiler. At that point, however, you've just written your own macro
system, and invoked Greenspun's 10th Law.

Thomas F. Burdick

unread,
Oct 6, 2003, 6:13:36 PM10/6/03
to
David Rush <dr...@aol.net> writes:

> On Mon, 06 Oct 2003, Raymond Wiker <Raymon...@fast.no> wrote:
> > Matthias <n...@spam.pls> writes:
> >> (In certain cases macros) can easily be misused.
> ...
> >> You have to know if you want a sharp knife (which may hurt you when
> >> misused) or a less sharper one (where it takes more effort to cut
> >> with).
> >
> > It is easier to hurt yourself with a blunt knife than a sharp
> > one.
>
> Actually I've noticed that I usually cut myself when I *switch* from
> a dull knife to a sharp one.

I don't think the truism about cutting yourself with dull vs sharp
knives means to say anything about superficial cuts. You don't lop
your finger off with a sharp knife, because you're handling it
carefully. With a dull knife, your best bet is to put your weight
behind it; that's also a good way to lose a finger / dump core.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Jock Cooper

unread,
Oct 6, 2003, 9:02:16 PM10/6/03
to
my-first-name...@jpl.nasa.gov (Erann Gat) writes:

I'm afraid it's very hard to give any convincing examples of the
utility of macros -- as long as you are sticking to trivial examples.
On the other hand, you can't exactly post real world complex examples
of how macros saved you time and LOC (we all have em) because reader's
eyes would just glaze over. I think macros are just another one of
CL's features that some most people just don't get until they actually
use them. But here's a small one:

I wrote about 60 lines worth of macro based code (including a few reader
macros) that allows me to write things like:

(with-dbconnection
(sql-loop-in-rows
"select col1, col2 from somewhere where something"
:my-package row-var "pfx"
...
...some code...
...))

In the "some code" section, the result columns' values are accessed by
#!pfx-colname (eg #!pfx-col1), or directly from row-var using
#?pfx-colname (which returns the position). Also, error handling code
can be automatically included by the macro code. How much time and
effort (and possible bugs) has this saved me? Well at least 60+ lines
or more of boilerplate every time I use this pattern.. Plus the expansions
for #!colname include error checks/warnings etc. -- all hidden from view.

Jock
---
www.fractal-recursions.com


Daniel P. M. Silva

unread,
Oct 6, 2003, 9:53:30 PM10/6/03
to
Erann Gat wrote:
> [...] But the point is that in pre-yield

> Python you were stuck until the langauge designers got around to adding
> it.
>
> I'll try to come up with a more convincing short example if I find some
> free time today.
>

Haven't some people implemented an entire class system as one huge macro?

- Daniel

Bengt Richter

unread,
Oct 7, 2003, 12:04:09 AM10/7/03
to
On 06 Oct 2003 12:54:30 +0200, Matthias <n...@spam.pls> wrote:

>gr...@cs.uwa.edu.au writes:
>
>> In comp.lang.functional Erann Gat <my-first-name...@jpl.nasa.gov> wrote:
>> :> I can't see why a LISP programmer would even want to write a macro.
>> : That's because you are approaching this with a fundamentally flawed
>> : assumption. Macros are mainly not used to make the syntax prettier
>> : (though they can be used for that). They are mainly used to add features
>> : to the language that cannot be added as functions.
>>
>> Really? Turing-completeness and all that... I presume you mean "cannot
>> so easily be added as functions", but even that would surprise me.
>> (Unless you mean cannot be added _to_Lisp_ as functions, because I don't
>> know as much as I'd like to about Lisp's capabilities and limitations.)
>
>IMHO, these discussions are less usefull when not accompanied by
>specific examples. What are these macros good for? Some examples
>where you might have difficulties with using ordinary functions:
>
>1.) Inventing new control structures (implement lazy data structures,

You mean like an object olazy with olazy.x and olazy.y, where x might
be an integer 123 and y might be the text of the latest bug python report
on sourceforge? Not so hard with properties (you'd proabably want to cache
the latest for y and not re-check for some reasonable interval, but that
doesn't change client code (unless you later decide you want the value to
be a tuple of (timestamp, text), etc.)

> implement declarative control structures, etc.)

You mean like case or such? It can be done, but Python could use a way
to define a nested functions that just use the local namespace of their lexically
enclosing function. Then case would be easy to build with a dictionary-based dispatch
of such functions.

Wild idea: It might be interesting to be able to do a kind of (quote thing) or 'thing
in Python, but to defer "trailer" evaluation (where trailer is what comes after an
object-specifying expression. E.g., in x.y[z+2](a=3) x has the trailer ".y[z+2](a=3)"
and x.y has the trailer [z+2](a=3), etc. Ok, you could currently write a class to
do deferred trailer evaluation in the form qt=QT(x.y, '[z+2](a=3)') and then
evaluate/unquote it with qt.value ot qt.evaluate(), etc., but you couldn't just
bind and pass a QT instance like an ordinary object and expect an automatic evaluation
on access, as if the quoted expression appeared in that context.

BTW, with trailer, I am just generalizing the first impulse, which was just to do it
for an attribute name, so as to be able to wrap property as well as ordinary attribute
accesses for unqualified (i.e., deferred-qualification -- we're not talking about
rebinding a name (e.g., x above) that is unknown at access time, since it was lost
when the leader object was pased to QT).

There is an ambiguity when assigning to a name that's bound to a QT object though,
i.e., whether to rebind the name as usual without considering its current binding,
or whether to notice the binding to a QT object, and do as-if-the-entire-trailer-
expression-were-there target processing for the assignment. The latter would make
for "interesting" programming ;-) To rebind such a name, you'd have to get at it
via an indirect route, much as you have to do with an object's attribute name if
it is bound to a property.

> => This one is rarely needed in everyday application programming and
> can easily be misused.
>
>2.) Serve as abbreviation of repeating code. Ever used a code
> generator? Discovered there was a bug in the generated code? Had
> to fix it at a zillion places?
> => Macros serve as extremely flexible code generators, and there
> is only one place to fix a bug.
> => Many Design Patterns can be implemented as macros, allowing you
> to have them explicitly in your code. This makes for better
> documentation and maintainability.

You can generate code many ways in Python. What use case are you thinking of?

>
>3.) Invent pleasant syntax in limited domains.
> => Some people don't like Lips' prefix syntax. It's changeable if you
> have macros.
> => This feature can also be misused.

You can do this also.

>
>4.) Do computations at compile time instead of at runtime.
> => Have heard about template metaprogramming in the C++ world?
> People do a lot to get fast performance by shifting computation
> to compile time. Macros do this effortlessly.

This also, but Python has so many possible compile times ;-)

>
>These are four specific examples which are not easy to do without
>macros. In all cases, implementing them classically will lead to code
>duplication with all the known maintainability issues. In some cases
>misuse will lead to unreadable or buggy code. Thus, macros are
>powerful tools for the hand of professionals. You have to know if you
>want a sharp knife (which may hurt you when misused) or a less sharper
>one (where it takes more effort to cut with).

Python is pretty sharp ;-)
I think we need some realistic use cases for your "specific" [categories of]
examples in order to compare how problems would be approached.

Regards,
Bengt Richter

Bengt Richter

unread,
Oct 7, 2003, 3:43:28 AM10/7/03
to

Just thought of this: a generator list comprehension, so your could write

[yield l for l in some_file_name if some_property(l)]

and get a generator that is the equivalent of your lines_with_some_property above.

I.e., in general you should be able to convert any list comprehension into a generator by
putting 'yield ' at the front. Has someone proposed this already? I seems a natural, unless
I am blindly optimistic, which is quite possible ;-)

>I have no problem with the assertion that macros are an important part
>of Lisp, but you seem to be arguing more generally that the lack of
>macros makes other languages like Python inferior because the literal
>translations of certain macro-based code are impossible or more
>cumbersome. For the present example, even that argument fails, but more
>generally you'll have to also convince me that even a freer poetic
>translation doesn't work.
>

Regards,
Bengt Richter

It is loading more messages.
0 new messages