tags:

views:

53

answers:

2

The condp clauses look like this:

      "plet" (make-adj 2 "ète")
      "iet"  (make-adj 2 "ète")
      "nin"  (make-adj 1 "gne")

I want to add the condition to the make-adj function call without repeating the condition twice in one line. I'd like a macro that turns this:

(test-make-adj "plet" 2 "ète")
(test-make-adj "iet" 2 "ète")
(test-make-adj "nin" 1 "gne")

Into this:

      "plet" (make-adj 2 "ète" "plet")
      "iet"  (make-adj 2 "ète" "iet")
      "nin"  (make-adj 1 "gne" "nin")
+1  A: 

First a function to make one of the condp clauses

(defn test-make-adj [x num y]
  `(~x (make-adj ~num ~y ~x)))

Then a macro to assemble the clauses into a condp expression

(defmacro adj-condp [pred expr & clauses]
  `(condp ~pred ~expr
     ~@(mapcat test-make-adj clauses)))

ps: i'm not at my repl so i cant test this, please edit :)

Arthur Ulfeldt
I've edited in a few fixes to the code. Apart from removing two minor bugs, I've replaced `(apply concat (map ...))` with `mapcat` and adjusted indentation as a matter of style. Hope you're ok with that.
Michał Marczyk
yea, thats fine :)
Arthur Ulfeldt
+3  A: 

condp has built-in functionality to support this kind of thing:

(condp #(if (= %1 %2) %1) condition
  "plet" :>> #(make-adj 2 "ète" %)
  "iet"  :>> #(make-adj 2 "ète" %)
  "nin"  :>> #(make-adj 1 "gne" %))

#(if (= %1 %2) %1) is a binary function which checks if its arguments are equal, returning the first argument if they are or nil otherwise.

:>> makes it so that the result of evaluating the predicate on condition and e.g. "plet" gets passed to the #(make-adj ...) function. With the above predicate this means that if (= "plet" condition) is true, then "plet" gets passed on to #(make-adj ...). See (doc condp) for more info.

If this still feels like too much typing, you can create a helper function:

(defn make-adj* [n s]
  (fn [c] (make-adj n s c))

Then use it like so:

(condp #(if (= %1 %2) %1) condition
  "plet" :>> (make-adj* 2 "ète")
  ...)
Michał Marczyk