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