I know this has been answered, and I already put one up myself, but thought I'd add the following as I had a play with it using monads again, and this seemed a good question to post against.
Reading this article on threading monads, I was able to come up with the following by extending the m->
macro defined in the article to create a threaded maybe monad for simpler usage. TBH it doesn't come any simpler than just using some->
but this was for personal curiosity.
OK, to start there's some one off boiler plate code to define, here (in case the article ever vanishes) is Giles' threaded monad definition:
(defn bind-monadic-expr-into-form [insert form]
(list 'm-bind insert
(if (seq? form)
`(fn [bound#] (~(first form) bound# ~@(rest form)))
`(fn [bound#] (~form bound#)))))
(defmacro m->
([m x]
`(with-monad ~m ~x))
([m x form]
`(with-monad ~m
~(bind-monadic-expr-into-form x form)))
([m x form & more]
`(m-> ~m (m-> ~m ~x ~form) ~@more)))
Now with this, you can define a threaded maybe macro as
(defmacro maybe->
([x] `(m-> ~maybe-m ~x))
([x form] `(m-> ~maybe-m ~x ~form))
([x form & more] `(maybe-> (maybe-> ~x ~form) ~@more)))
And use it like:
(maybe-> 1 inc)
=> 2
(maybe-> [1 2] (#(map inc %)))
=> (2 3)
(defn f1 [x] (+ 1 x))
(maybe-> 1 f1 f1)
=> 3
(maybe-> 1 f1 ((constantly nil)) f1)
=> nil
(maybe-> {:a 1 :b 2} :c inc)
=> nil
There's absolutely no advantage in using this over some->
in this context, but the m->
monad does add some interesting abilities in being able to create a fail->
macro as in the article I linked, which offers more than just "nil" as a return, giving you ability to differentiate the failure reason.