Kevin
Kevin

Reputation: 25269

clojure threading operator

Lets say I want to use the threading operator to thread a map through a series of function calls. All the functions take the map as a first parameter (good) but one function does not conform to the correct signature (say it takes the map as the last parameter). What is the best way to "fix" the function signature?

Upvotes: 6

Views: 2125

Answers (3)

Mrinal Saurabh
Mrinal Saurabh

Reputation: 978

I think people tend to underestimate the kind of threading operators available in clojure. So let me introduce you to as-> threading operator.

The as-> thread creates a variable which takes the value of the each function call in the threading steps. Example,

(as-> 2 x        ;; x = 2
      (+ 3 x)    ;; x = 5
      (- x 1)    ;; x = 4
      (/ x 2)    ;; x = 2
      (+ x x x)) ;; x = 6

The output of the above operation is x i.e. 6.

Upvotes: 7

amalloy
amalloy

Reputation: 91857

(-> your-arg
    (fn1 arg2 arg3)
    (fn2 arg5 arg6)
    (->> (fn3 arg7 arg8)
         (fn4 arg10 arg11)))

Seems nicer than the version with ->> "before" ->, to me. Another thing you can do is write some basic argument-reordering functions, and use those to create versions of fn3 and fn4 that take their arguments in the order you want.

Upvotes: 1

Paul
Paul

Reputation: 8172

The reader macro #() for anonymus functions is a good candidate here:

(-> your-arg
  (fn1 arg2 arg3)
  (fn2 arg4 arg5)
  (#(fn3 arg6 arg7 %)) )

It is flexible and adds little visual noise. You can of course do many different things, in this case partial function application would also work:

(-> your-arg
  (fn1 arg2 arg3)
  ((partial fn2 arg4 arg5)))

There is also the ->> macro which threads the first expression into the last position. Of course in your use case this doesn't help much, as you would have to adjust some of the function calls. However if you are chaining many functions that should take the expression as the first argument and then many functions that take the expression as the last argument you could do something like

(->>
  (-> your-arg
    (fn1 arg2 arg3)
    (fn2 arg5 arg6))
  (fn3 arg7 arg8)
  (fn4 arg10 arg11))

EDIT: Added extra parenthesis in first example.

Upvotes: 9

Related Questions