Skip to content

Simple Macro

June 15, 2010

I recently had a requirement for a version of cond that took a predicate expression and passed the clause as a parameter. While condp was close it didn’t really match what I was trying to do. Macros are still new to me so this was a good learning experience.

Here’s an example of the code I wished to write:

(conde app/key-pressed?
	:up (move-player state 1 -1)
	:down (move-player state 1 1))

Alternatively the predicate can be a form, the clause is added to the end of the form. For example:

(conde (= 2)
       1 (print "was one")
       2 (print "was two"))

Since cond is almost what I wanted I took that code and altered it to get the following:

(defmacro conde
  "Takes a predicate form and a set of test/expr pairs. It
  evaluates each test one at a time against the predicate.  If a
  test returns logical true, conde evaluates and returns the value
  of the corresponding expr and doesn't evaluate any of the other
  tests or exprs. (cond) returns nil."
  {:added "1.0"} [pred & clauses]
  (when clauses
    (let [pred (if (not (seq? pred)) (list pred) pred)]
      (list 'if `(~@pred ~(first clauses))
            (if (next clauses)
              (second clauses)
              (throw (IllegalArgumentException.
                      "cond requires an even number of forms")))
             (cons pred (next (next clauses))))))))

In the end the changes are pretty simple but it took me a bit of working out at the time. I’m just not used to macro programming yet. So some questions to the lazy web:

Firstly: can condp be used to achieve the same thing?

Secondly: the code checks whether the predicate is a sequence, this seems a little awkward. Is there a better way of doing this?

From → Clojure

One Comment
  1. Nguy?n Tu?n Anh permalink

    This seems to work (using condp):
    (defmacro condd [pred & clauses]
    `(letfn [(predd# [test-expr# expr#]
    (->> test-expr# ~pred))]
    (condp predd# nil

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

%d bloggers like this: