I've recently had a need for something like that in my own code. The "real" solution to that problem in the functional programming world is known as the maybe monad. Since I just needed a quick and dirty solution and I have not wrapped my head around monads yet, here's what I did :
(defmacro maybe-> "Sort of like a maybe monad, but without a monad. Takes an initial value and a list of functions with their arguments, and returns the result of applying each function to the result of the preceding one as long as there is no nil value. Returns nil if there ever is a nil in the chain of values." [init & fns] (reduce (fn [acc [op & args]] `(if-not (nil? ~acc) (~op ~acc ~@args))) init fns)) I did not have a need for "as->"-like functionality. On 23 March 2013 05:54, Mikera <mike.r.anderson...@gmail.com> wrote: > You can get quite a long way with just "if-let" "and" and "or" to express > the bailout logic. > > Examples I find myself using all the time: > > ;; fallback / default values > (or (maybe-make-value) (make-fallback-value) (error "this shouldn't > happen!")) > > ;; bailout with nil return (assumes you are running operations for side > effects, and nil return means failure) > (and (operation1) (operation2) (operation3) :success) > > ;; let a value, with potential defaults > (if-let [value (or passed-value (try-to-find-default-value))] ....) > > Apart from that, I found myself writing a few macros to allow early bailouts > from computations. My favourite currently is the "and-as->" macro, which > works like this: > > (and-as-> (some-initial-value-expression) symbol > (do-something-with symbol) > (some-thing-else symbol) > (reduce some-fn symbol some-seq)) > > At each step, symbol is rebound to the result of the expression (like > "as->") unless the result is nil, in which case the whole expression bails > out and returns nil. So it is like a cross between "and" as "as->". > > > > On Saturday, 23 March 2013 11:19:28 UTC+8, Russell Mull wrote: >> >> Hi Clojurians, >> >> I'm relatively new to the language and am trying to get used to its >> idioms. One thing I'm accustomed to doing in things like java and C# is >> checking values for validity and then bailing out early if they don't make >> sense. For example, without this idiom in java you might do: >> >> Object doSomething() { >> >> Integer a = someComputation(); >> if(a != null) { >> Integer b = anotherComputation(a, 42); >> if(b != null && b.intValue() >= 0) { >> return a / b; >> } >> else { >> return null; >> } >> } >> else { >> return null; >> } >> } >> >> ... which is really only desirable if you believe in the "one exit point" >> school of imperative programming. It is of course much better to do this: >> Object doSomething() { >> Integer a = someComputation(); >> if(a == null) { return null; } >> >> Integer b = anotherComputation(a, 42); >> if(b == null || b.intValue == 0) { return null; } >> >> return a / b; >> } >> >> >> >> ... which is much more literate. In Clojure, I have to write what is >> effectively the first form: >> >> (let [a (some-computation)] >> (if (nil? a) >> nil >> (let [b (another-computation a 42)] >> (if (or (nil? b) (= b 0)) >> nil >> (/ a b))))) >> >> While more concise, it suffers the same readability problems as the first >> java version. I can easily imagine a macro to support this idiom: >> >> (let-check [a (some-computation) >> :check (nil? a) nil >> b (another-computation a 42) >> :check (or (nil? b) (< b 0)) nil] >> (/ a b)) >> >> >> Which leads me to my question: does such a construct already exist? Or >> perhaps am I doing it wrong? I've googled around for this, but I'm not >> exactly sure what it's called. >> >> Cheers, >> >> Russell > > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.