Skip to content

Instantly share code, notes, and snippets.

@pyrtsa
Last active August 29, 2015 14:04
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pyrtsa/1af9fdd56267a3631b0c to your computer and use it in GitHub Desktop.
Save pyrtsa/1af9fdd56267a3631b0c to your computer and use it in GitHub Desktop.
A short-circuiting let expression in Clojure
;; This is probably either a silly idea or a foolish implementation of an okay one.
(defn ret*
[bindings & body]
(if-let [[k v & more] (not-empty bindings)]
`(let [k# ~v]
(if (reduced? k#)
k#
(let [~k k#]
~(apply ret* more body))))
`(do ~@body)))
(defmacro ret
"(ret [bindings...] body...) - Like clojure.core/let but if one of the
bindings evaluates to `(clojure.core/reduced something)`, then that
`something` is returned and no further bindings nor the `body` are
evaluated."
[bindings & body]
`(let [r# ~(apply ret* bindings body)]
(if (reduced? r#)
@r#
r#)))
;; Example (see https://gist.github.com/gws/3d091805d6ba1b359c5d)
(defn wrap-user
"Add user information to the request map if logged in."
[handler]
(fn [request]
(ret [db (get-in request [:myapp :system :db])
ident (or (get-in request [:session ::friend/identity :current])
(reduced (handler request))) ;; short circuit #1
user (or (magic/user-by-id db ident)
(reduced (handler request)))] ;; short circuit #2
(handler (assoc-in request [:myapp :user] user)))))
;; Or, adding another `let` (which is, again, easy to convert into a `ret`
;; for whatever reason needed) and getting rid of repetitive repetition:
(defn wrap-user
"Add user information to the request map if logged in."
[handler]
(fn [request]
(let [req (ret [db (get-in request [:myapp :system :db])
ident (or (get-in request [:session ::friend/identity :current])
(reduced nil))
user (or (magic/user-by-id db ident)
(reduced nil))]
(assoc-in request [:myapp :user] user))]
(handler (or req request)))) ;; A single return point, arguably makes it easier to read.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment