1
votes

I am currently reading the book "The Joy of Clojure", 2nd edition. In Chapter 7 "Functional Programming", I came across the following function that was used to describe function composition.

(defn fnth [n]
  (apply comp
         (cons first
               (take (dec n) (repeat rest)))))

((fnth 5) '[a b c d e])
;=> e

I don't fully understand the mechanics of that function. Trying to reproduce the inner scope without using comp, the function produces a repeating list:

(take (dec 5) (repeat (rest '[a b c d e])))
;=> ((b c d e) (b c d e) (b c d e) (b c d e))

What is the point of attaching first to that repeating list by using comp? Is this also the last part of the function list which is fed into comp?

(first (take (dec 5) (repeat (rest '[a b c d e]))))
=> (b c d e)

Thank you in advance!

2

2 Answers

5
votes

The fnth function works by constructing a sequence of the form (first rest rest ... rest) i.e. first followed by n - 1 rests. It then composes them into a single function by applying comp. For (fnth 5) this is

(apply comp (first rest rest rest rest))

When the result function is called on the vector [a b c d e] the resulting application is

(first (rest (rest (rest (rest [a b c d e])))))

i.e. the first element of the 4th tail of the input sequence.

Your attempted reconstruction only calls rest once and then reapeats the returned sequence instead.

5
votes

This fnth does not (itself) return the nth item of a collection, but rather produces a function that does so.

What function should it produce to get the 1st item?

(defn nth-1 [coll]
    (first coll))
    

What function should it produce to get the 2nd item?

(defn nth-2 [coll]
    (first (rest coll)))
    

What function should it produce to get the 3rd item?

(defn nth-3 [coll]
    (first (rest (rest coll))))
    

So there's a pattern! But the nesting would be a challenge for fnth.

An equivalent formulation for (first (rest (rest x))) is ((comp first rest rest) x). Now we can write nth-3 as

(defn nth-3 [coll]
    ((comp first rest rest) coll))
    

With this approach fnth is easier to write. But it would be easier still if we rewrote (comp first rest rest) as (apply comp [first rest rest]). There! Now fnth needs is to make a list of first + the right number of rest's, and apply comp to that list.