user1391110
user1391110

Reputation:

Apply a list of functions to a value

I'm looking for something that is probably very well defined in Clojure (in the Lisp world at large in fact) but I don't have enough experience or culture to get on the right track and Google hasn't been very helpful so far.

Let's say I have three simple forms:

(defn add-one   [v] (+ v 1))
(defn add-two   [v] (+ v 2))
(defn add-three [v] (+ v 3))

Out of convenience, they are stored in a vector. In the real world, that vector would vary depending on the context:

(def operations
  [add-one
   add-two
   add-three])

And I also have an initial value:

(def value 42)

Now, I would like to apply all the functions in that vector to that value and get the result of the combined operations:

(loop [ops operations
       val value]
  (if (empty? ops)
    val
    (recur (rest ops)
           ((first ops) val))))

While this does work, I'm surprised there isn't a higher level form just for that. I've looked all over the place but couldn't find anything.

Upvotes: 2

Views: 760

Answers (2)

Thumbnail
Thumbnail

Reputation: 13483

The functional phrase you are searching for is (apply comp operations):

((apply comp operations) 42)
;48

Your loop does work if you feed it 42 for value:

(loop [ops operations
       val 42]
  (if (empty? ops)
    val
    (recur (rest ops)
           ((first ops) val))))
;48

This applies the operations in the opposite order from comp.

... As does using reduce:

(reduce (fn [v f] (f v)) 42 operations)
;48

If you look at the source code for comp, you'll find that the general case essentially executes a loop similar to yours upon a reversed list of the supplied functions.

Upvotes: 8

Mark Karpov
Mark Karpov

Reputation: 7599

'In Lisp world at large' you can use reduce:

user> (reduce (fn [x y] (y x)) 5 [inc inc inc inc])
;; => 9

This may look not so sexy, but it works everywhere with minor variations (this is Common Lisp, for example):

CL-USER> (reduce (lambda (x y) (funcall y x))
                 '(1+ 1+ 1+ 1+)
                 :initial-value 5)
9

Upvotes: 1

Related Questions