Matthew
Matthew

Reputation: 153

How do I define a function within a function in Clojure and reference that function?

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

Answers (2)

Arthur Ulfeldt
Arthur Ulfeldt

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

Matt Fenwick
Matt Fenwick

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

Related Questions