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

Thomas Bellman bellman at lysator.liu.se
Tue May 15 21:17:01 EDT 2001


"Terry Reedy" <reedy37 at home.com> writes:

> What I know about Lisp macros is what I have gleaned from this thread,
> which isn't too much yet.  How is the above different from writing and
> calling a function.  IE

> def new_state(tag):
>   if tracing: store_tracing_info()
>   goto(tag)
> new_state(tag)

Mr. Nonexistence wasn't using a particularly good example.  LISP
macros come to their advantage when you want to implement control
structures: "functions" that take code blocks as arguments.

In Python you can pass functions as arguments to other functions
(you can do that in LISP too, of course; LISP more or less
invented that concept), so you can do more or less the same thing
in Python.  However, you get much more textual overhead if you
need to define a gazilion small functions and pass them to a
control structure function.

You could define a function acting as the switch statement in C:

    def switch(value, cases):
	cases[value]()

But *using* that isn't very fun:

    def say_one(): print "One"
    def say_two(): print "Two"
    def say_three(): print "Three"
    def case_zero():
	global x
	x = x + 17
	print "ZERO!"
    switch(i,
	   { 0: case_zero,
	     1: say_one,
	     2: say_two,
	     3: say_three })

What you *would* have liked, is to define a switch "keyword" so
you could have written that as

    switch i:
	case 0:
	    x = x + 17
	    print "ZERO!"
	case 1:
	    print "One"
	case 2:
	    print "Two"
	case 3:
	    print "Three"

Note also that here I didn't have to make x a global variable,
but can access the local variable x.  Just as in an if statement.

In LISP, you easily do that:

    (defmacro switch (value &rest cases)
      (let ((symbol (gensym)))
	`(let ((,symbol ,value))
	   ,(cons 'cond
		  (mapcar (lambda (case)
			    `((= ,symbol ,(car case)) ,@(cdr case)))
			  cases)))))

(Hmm, it's probably possible to write that a lot prettier, but I
don't feel like spending that time now.)

You use it like this:

    (switch (- (elt array idx) 3)
      (0 (setq x (+ x 17))
	 (print "ZERO!"))
      (1 (print "One"))
      (2 (print "Two"))
      (3 (print "Three")))

Now, go dream up more complicated control structures than a
simple switch statement. :-)


-- 
Thomas Bellman,   Lysator Computer Club,   Linköping University,  Sweden
"God is real, but Jesus is an integer."      !  bellman @ lysator.liu.se
                                             !  Make Love -- Nicht Wahr!



More information about the Python-list mailing list