Reputation: 6776
Sorry if this question doesn't make any sense.
I'm currently in the midst of writing a small application and I want to 'chain' some functions together that form a wider computation.
So for example, I have a function that calls a webservice and returns a hash-map
as a result, or nil
if the was an error or something went wrong. The next function in the chain takes the map and does some further processing and then passes it on to the next function...and so on.
The thing is if the first function fails, it's going to pass nil
to the next function and that will throw a nullpointer (or whatever) and I don't want it to even reach this stage.
So in other words I want the whole computation to fail if one item in the chain fails.
e.g.
;successful computation = function1 returns W -> function2 returns X -> function3 returns Y -> function4 returns Z -> Z
;failed computation = function1 returns W -> function2 returns X -> function3 returns nil -> nil
(-> (function1 "http://webservice.com") (function2) (function3) (function4))
The thing is I don't want to be littering each of my functions with if(nil? arg)
at the start, ideally I'd like an abstraction that could take care of that for me but I'm not really clued up on what's available in Clojure
I was thinking of adopting the Scala style Option
type that can either be Some(value)
or None
but I'd still need to litter my code with these checks at the start
Any ideas or replies would be really appreciated
Upvotes: 5
Views: 147
Reputation: 14476
You could define a helper function for chaining the function calls and checking for nil values in between:
(defn chain [v & functions]
(cond (nil? v) nil
(empty? functions) v
:else (recur ((first functions) v) (rest functions))))
Then call it like this:
(chain "http://webservice.com" function1 function2 function3 function4)
Upvotes: 1
Reputation: 17773
clojure.contrib.core has the -?>
macro that does exactly what you want.
See http://clojuredocs.org/clojure_contrib/clojure.contrib.core/-_q%3E
Upvotes: 4
Reputation: 15759
Clojure Contrib's algo.monad
includes an implementation of the monad that Scala calls Option
. It is called maybe-m
and works by treating nil
as None
. You can use it like this:
(ns mulk.monads-test
(:refer-clojure)
(:use clojure.repl
clojure.algo.monads))
(defn function1 [x]
x)
(defn function2 [x]
(+ x 10))
(defn function3 [x]
(* x 2))
(defn calc-stuff [thing]
(domonad maybe-m
[x1 (function1 thing)
x2 (function2 x1)
x3 (function3 (+ x2 10))]
x3))
(calc-stuff 10) ;=> 60
(calc-stuff nil) ;=> nil
Upvotes: 4