Lisp Programming Trick #2

Recursive Condition

This little trick hit me when I was perusing PCL. Specifically, the when selector.

(defun rec-cond (key)
    ((eq key :before) (format nil "executing before" ))
    ((eq key :during) (format nil "executing during" ))
    ((eq key :after) (format nil "executing after" ))

    ((eq key :set-up) (rec-cond :before))
    ((eq key :init) (rec-cond :before))

    ((eq key :teardown) (rec-cond :after))

    (t (error (format nil "unknown command: ~A" key))))

This overloads keyword symbols so that you more than one keyword can execute the same code.Syntactic Sugar

(defun num (key)
    ((eq key :zero) 0)
    ((eq key :one) 1)
    ((eq key :two) (1+ (num :one)))
    ((eq key :three) (1+ (num :two)))
    ((eq key :four) (1+ (num :three)))
    ((eq key :five) (1+ (num :four)))
    ((eq key :six) (1+ (num :five)))
    ((eq key :seven) (1+ (num :six)))
    ((eq key :eight) (1+ (num :seven)))
    ((eq key :nine) (1+ (num :eight)))
    (t (error (format nil "unknown number keyword: ~A" key)))))

    (assert-equal 0 (num :zero))
    (assert-equal 1 (num :one))
    (assert-equal 2 (num :two))
    (assert-equal 3 (num :three))
    (assert-equal 4 (num :four))
    (assert-equal 5 (num :five))
    (assert-equal 6 (num :six))
    (assert-equal 7 (num :seven))
    (assert-equal 8 (num :eight))
    (assert-equal 9 (num :nine))
    (assert-error 'simple-error (num :haha)))

    (assert-equal 5 (+ (num :two) (num :three)))
    (assert-equal 5 (- (num :eight) (num :three)))
    (assert-equal 6 (* (num :two) (num :three)))
    (assert-equal 2 (/ (num :six) (num :three))))))

But who the hell wants to write num function and then keyword.

This might me a little better.

(defmacro with-numbers (&rest rest)
  `(let ((zero 0)
         (one 1)
         (two 2)
         (three 3)
         (four 4)
         (five 5)
         (six 6)
         (seven 7)
         (eight 8)
         (nine 9))

     (assert-equal 0 zero)
     (assert-equal 1 one)
     (assert-equal 2 two)
     (assert-equal 3 three)
     (assert-equal 4 four)
     (assert-equal 5 five)
     (assert-equal 6 six)
     (assert-equal 7 seven)
     (assert-equal 8 eight)
     (assert-equal 9 nine)))

     (assert-equal 5 (+ two three))
     (assert-equal 5 (- eight three))
     (assert-equal 6 (* two three))
     (assert-equal 2 (/ six three)))))

I believe that if you use format you can also get something similar. Just intern string to symbol.

(intern (string-upcase (format nil "~r" 0))

I think I’m going to start using different titles for these type of posts.

What do you think?

4 Responses to Lisp Programming Trick #2

  1. Zach Beane says:

    ECASE would be more appropriate.

    A bare SETQ with no special declaration has undefined consequences.

    • gutzofter says:

      That’s the problem with trying to find a binding for the numbers that also shows off something that you think is cool. I’ve redone the example and got rid of the SETQs. Thanks for you feedback

  2. Zach Beane says:

    How about that ECASE update now too?

    Also ERROR by default can handle formatting its message.

    I’d probably make NUM like this:

    (or (position num
    #(:zero :one :two :three :four :five :six :seven :eight :nine))
    (error “~A is not a number keyword” num))

  3. Zach Beane says:

    More likely: (error “~S is not a number keyword” num)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: