Reputation: 153
I wrote a function to compute the symmetric difference of two sets (one of the problems on the 4clojure site). The function passed the unit tests, but it's not as clean as I would like, given that I have duplicated code.
(fn [x y] (set (concat
(keep-indexed #(if (nil? (get y %2)) %2) x)
(keep-indexed #(if (nil? (get x %2)) %2) y))))
Obviously I would prefer something like:
(fn [x y] (set (concat (diff x y) (diff y x))))
Where the diff function is defined and referenced "inline", but I don't know how to do that in one fn block.
Upvotes: 15
Views: 4584
Reputation: 91534
One of the features that makes Clojure a lisp (and a functional language in general) is that functions are first class things in Clojure specifically they are Objects. When you make a function with (defn name [arg] ...)
if builds the function and then stored it in a var so you can find it later from anywhere in your program. it's a lot like this:
(def name (fn [arg] ...))
now name contains a function that is widely accessible. Functions don't have to be stored in vars, especially if they are only needed within your function. In that case it makes more sense to bind the function to a local name as with Matt Fenwick answer.
(let [name (fn [agr] ...)] ...)
the letfn
macro makes this more elegant.
The important part is to understand that functions are Objects that are stored in things, and you can choose the container that suits your needs.
Upvotes: 11
Reputation: 49085
Use a let
or letfn
:
(fn [x y]
(let [diff (... function body here ...)]
(set
(concat (diff x y) (diff y x)))))
Upvotes: 23