Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure's -> (arrow) operator and optional operations

I've run in several situations where I want to do a chain of operations on an object with optional functions. "->" works great for sequences of commands on the same object (ex. (c (b (a x))) becomes (-> x a b c) ), except if some operations are optional. For example, suppose I wanted to do:

(c
  (if (> (a x) 2)
     (b (a x))
     (a x)
     )
  )

Is there any way to do that in a clearer fashion using an operation like "->"?

like image 553
redfish64 Avatar asked Jul 06 '13 22:07

redfish64


1 Answers

You can do it with cond->, newly introduced in Clojure 1.5:

(cond-> x
  true        a
  (> (a x) 2) b
  true        c)

Or, better,

(-> x
  a
  (cond-> (> (a x) 2) b)
  c)

Meaning, "take x, thread it through a, take the result and thread it through b if (> (a x) 2) or else leave it unchanged, finally take what you've got and thread it through c".

In other words, cond-> is like ->, except instead of single forms to thread your expression through it takes test+form pairs, where the form is skipped if test is falsey and used for threading if test is truthy:

(cond-> x
  test-1 form-1
  test-2 form-2)

;; if test-1 is truthy and test-2 is falsey, output is as if from
(-> x test-1)

;; if it's the other way around, output is as if from
(-> x test-2)

;; if both tests are truthy:
(-> x test-1 test-2)

;; if both tests are falsey:
x
like image 183
Michał Marczyk Avatar answered Nov 20 '22 16:11

Michał Marczyk