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
             'yourns/conde
             (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?

Advertisements

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
    ~@clauses)))

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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: