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 x
.
So:
# Calulate the value of the polynomial
# 2x^2+3x-1
# where x = 3
((polynomial 2 3 -1) 3)
# => 26.0
I use 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 x
.
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 (fn ..)
.
(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.