Why is Python popular, while Lisp and Scheme aren't?

Pascal Costanza costanza at web.de
Sat Nov 9 20:46:04 EST 2002


Rocco Moretti wrote:
> "Johannes Grødem <johs+n at ifi.uio.no> wrote in message news:<lzznsipz4s.fsf at unity.copyleft.no>...
> 
>>Because Lisp has a powerful macro system, it is actually possible to
>>have an infix-macro, which lets you use infix-syntax.  And you can
>>write macros to support all sorts of weird syntax, if you want.
> 
> I've heard this argument a number of times, and have never really
> bought it. To me it seems equivalent to saying "Because (Brainf*ck/
> Intercal/ Unlambda/ Malbourge /etc) are Turing Complete, you can write
> any program in them." Sure, you *can*, but why bother?

...because macros in Common Lisp allow you to do extremely powerful 
things and write very compact code.

[...]
> It's doubly hard when beginning Lisp books only teach the prefix
> notation - the beginner could change it, but who, thus thouroghly
> vexed, has the stamina to wait until chapter 23 to learn how? That's
> why the common rebuttal directed toward Lisp critics is that they
> don't *really* know the language. Lisp is a powerful language, but you
> have to have the patience and the masochism to make it all the way to
> chapter 23.

Then throw that book away and buy a better one. ;-)

Or better yet, download the freely available "On Lisp" by Paul Graham at 
http://www.paulgraham.com/onlisp.html which is the best book on macros 
in Common Lisp. (It introduces them in chapter 7, that's 16 chapters 
earlier! ;)

The core is extremely simple:

This is a piece of program in Lisp: (gethash "key" table)
This is some data in Lisp, a list: '(gethash "key" table)

In the first example, we have a call of the function gethash with 
arguments "key" and table. In the second example, we have a list with 
the three elements gethash, "key" and table.

(BTW, this is exactly the reason why Lisp has this seemingly strange 
syntax - you can easily switch between program representation and data 
representation. On the conceptual level, Lisp makes no difference 
between data and programs.)

In the first example, "key" evaluates to a string and table is a 
variable that (hopefully) evaluates to a hash table. In the second 
example, none of the three elements are evaluated, but they are taken as is.

Sometimes you need lists with some elements evaluated and some not. Here 
is an example: `(gethash "key" ,table) - here, gethash and "key" are not 
evaluated but table is.

So when you have a function definition (defun f (x) (* x x)), everytime 
the Lisp compiler sees for example (f 5), it translates this to a call 
to the function f with argument 5 (or it inlines the call, depending on 
settings of the environment).

On the other hand, when you have a macro definition (defmacro f (x) `(* 
,x ,x)), everytime the Lisp compiler sees (f 5), it calls the macro 
function f with the list '(f 5) at compile time. The macro function 
returns '(* 5 5) and the compiler takes this as the code that it needs 
to compile instead of the original code. (Of course, the result of a 
macro function may include further macro calls, and so on.)

So here is a neat toy example for a good Common Lisp macro. Assume you 
have two functions lock and unlock to protect objects from some unwanted 
access. For example:

(lock ouput)
(write-line "Hello, World!" output)
(write-line "Hi, everybody else!" output)
(unlock output)

A nicer way to do this is to write a macro as follows.

(defmacro with-locked-object (object &rest code)
    `((lock ,object)
      , at code
      (unlock ,object)))

Here, code is a so-called rest arguments - a list of all arguments after 
the already processed arguments (in this case object). The splice 
operator ,@ takes a list, unwraps one pair of brackets and puts this 
list into the surrounding list.

So now you can do the following.

(with-locked-object output
    (write-line "Hello, World!" output)
    (write-line "Hi, everybody else!" output))

Here, the macro function with-locked-object gets output (unevaluated) 
and the list '((write-line "..." output) (write-line "..." output)) as 
arguments and creates our original code as output. The nice thing about 
this macro is that it frees you from the need to remember to unlock your 
object properly. We have essentially defined a language extension!

(This is the way Lisp programmers usually work - they create a kind of 
domain-specific language for the problem at hand and use that language 
for solving the problem.)


Pascal

-- 
Given any rule, however ‘fundamental’ or ‘necessary’ for science, there 
are always circumstances when it is advisable not only to ignore the 
rule, but to adopt its opposite. - Paul Feyerabend




More information about the Python-list mailing list