Last active
August 29, 2015 14:04
-
-
Save pyrtsa/1af9fdd56267a3631b0c to your computer and use it in GitHub Desktop.
A short-circuiting let expression in Clojure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 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