Caveat lector: skip if you're not interested in the experiences of someone learning Clojure and functional-programming.
At the moment I am reading the excellent Clojure Programming from O'Reilly. It was one of the first books I bought but I found it a little formidable as an introduction to Clojure. I'm finding it a lot more digestible now.
In it I came across an example of the excellently named
juxt function. Reading the docs I found it a little difficult to get my head around:
Takes a set of functions and returns a fn that is the juxtaposition of those fns. The returned fn takes a variable number of args, and returns a vector containing the result of applying each fn to the args (left-to-right).
It's actually really simple but the use of the word juxtaposition made me think it more complicated than it is. To whit:
juxtapose (verb) place or deal with close together for contrasting effect: black-and-white photos of slums were starkly juxtaposed with colour images.
But what was the contrasting effect?
The O'Reilly example was:
(juxt quot rem)
as a replacement for:
(defn euclidian-division [x y] [(quot x y) (rem x y)])
and, as I played with the output of the function, the penny starts to drop. Then I see it, that the contrast, the juxtaposition, is in how each of the functions passed to
juxt interprets its argument(s).
It seems to me that
juxt is like a
map generator. But where
map is about mapping a function across a sequence of values,
juxt returns a function that maps a sequence of functions across its arguments.
So now I felt I understood it but I wondered how I could make use of it myself. I use
map all the time but in what circumstance do you need to apply a series of functions over a value?
In calculating the value of a polynomial the degrees are, essentially, functions of an argument
x where x is raised to the degree and multiplied by a constant, e.g.
The result of each of these degree functions is summed to get the total value of the polynomial for
x. In Clojure terms we could say this is summing the juxtaposition of the degree functions which might look a bit like:
(defn polynomial [& degrees] (comp (partial apply +) (apply juxt (map-indexed (fn [degree multiplier] (fn [x] (* multiplier (Math/pow x degree)))) (rseq (vec degrees))))))
polynomial is a function that takes as it's arguments the constant multiplier of each of the degrees of a polynomial starting with the highest and ending with the power zero. It returns a function that takes an argument
x and returns the value of the given polynomial for
# Calulate the value of the polynomial # 2x^2+3x-1 # where x = 3 ((polynomial 2 3 -1) 3) # => 26.0
juxt to create a function that takes an argument and return a sequence of values obtained by passing the argument to each of a sequence of anonymous functions that calculates the value of one degree of the polynomial:
(fn [x] (* multiplier (Math/pow x degree)))
I then use
comp to compose the function returned by
juxt with a function that sums the individual components to give the total value for the polynomial at
I'm quite happy that I understand
juxt, found a reasonable way of using it, and also managed to get
comp in there too!
Update: Marshall Bockrath-Vandegrift (llasram from the #clojure IRC channel on Freenode) came up an alternative implementation using
->> threading macro to pull the function pipeline inside out, replacing the more cumbersome
(rseq (vec degrees)) with
(reverse degrees) and using Clojure's anonymous function literal syntax
#(..) instead of
(defn polynomial [& degrees] (->> (reverse degrees) (map-indexed (fn [i m] #(* m (Math/pow % i)))) (apply juxt) (comp (partial apply +))))
I think this one is more readable and probably more idiomatic clojure. Thanks llasram.