What can you do in LISP that you can't do in Python

Gareth McCaughan Gareth.McCaughan at pobox.com
Mon May 14 17:14:53 EDT 2001


Richard P. Muller wrote:

> I read Paul Graham's excellent article
> (http://www.paulgraham.com/paulgraham/avg.html) on using LISP to write
> what became the Yahoo!Stores website. One of the central points is that
> there are some things (macros) that you can do in LISP that you can't do
> in other languages. This motivated me to learn a bit about LISP. I chose
> the Scheme dialect, because it seemed to have the best documentation
> available for free. 
> 
> However, thus far I can't see anything that I could do in Scheme that I
> couldn't do in Python. From the thread on LISP I've seen a lot of
> comments that have suggested that I should have started with Common Lisp
> instead of Scheme -- so maybe that's the problem. But can someone give
> me a short example of something that I can do in LISP that I couldn't do
> in Python?

This is CL, not Scheme, but although Scheme's macros are
less powerful than CL's it's something you could do in
Scheme too.

Imagine that CL didn't already have WITH-OPEN-FILE,
which basically encapsulates an idiom like this one:

    f = open(...)
    try:
      ...
    finally:
      f.close()

Then you could define it for yourself, along the
following lines:

    (defmacro with-open-file ((stream-name file-name &rest options) &body body)
      `(let ((,stream-name (open ,file-name , at options)))
         (unwind-protect
           (progn , at body)
           (close ,stream-name))))

and, bingo, you can now do

    (with-open-file (in "foo.py" :direction :input)
      (with-open-file (out "foo.f" :direction :output)
        (translate 'python 'fortran in out)))

and get the automatic-closing behaviour without ever
having to write it in full. More to the point, you
could write similar macros to deal with other sorts
of resource deallocation: network sockets, locks for
multithread/multiprocess code, whatever.

Or (this is CL-only): suppose you find the standard way
of writing anonymous functions too verbose. Then:

    (defun split-list-at (list item)
      (let ((before nil))
        (loop for tail on list
              for this = (first tail)
              when (eql this item)
                return (values (nreverse before) (rest tail))
              else do (push this before))))

    (set-macro-character #\} (get-macro-character #\)))

    (set-macro-character #\{
      (lambda (stream char)
        (declare (ignore char))
        (multiple-value-bind (args body)
                             (split-list-at (read-delimited-list #\} stream t)
                                            '->)
          `(lambda ,args
             (declare (ignorable . ,args))
             . ,body))))

and now you can say things like

    (mapcar {a b -> (list a b)} '(1 2 3 4) '(a b c d))

returning ((1 a) (2 b) (3 c) (4 d)).

Taking all this stuff an order of magnitude (or several)
further, there's Richard Waters's SERIES package which
lets you write code that looks like it's manipulating
sequences but in which all the intermediate sequences
get compiled away.

It's possible to write incomprehensible, unmaintainable
code by abusing macros. It's also possible to fill in
holes in the language and to adapt it to your problem
domain.

-- 
Gareth McCaughan  Gareth.McCaughan at pobox.com
.sig under construc



More information about the Python-list mailing list