Skip to content

Instantly share code, notes, and snippets.

@c-garcia
Last active August 29, 2015 14:22
Show Gist options
  • Save c-garcia/f7fa98358e5555055afa to your computer and use it in GitHub Desktop.
Save c-garcia/f7fa98358e5555055afa to your computer and use it in GitHub Desktop.
Macro to pipe functions through core.async channels
(defmacro validate-args
[exp msg]
`(when-not ~exp
(throw (IllegalArgumentException. ~msg))))
(defmacro chan-pipe
;; first and last body functions will be prepended an argument (the out and in channel)
;; internal body functions will be prepended two arguments in and out channels
[bindings & body]
(validate-args (vector? bindings) "bindings should be a vector")
(validate-args (= (mod (count bindings) 2) 0) "bindings should have an even number of items")
(validate-args (>= (count body) 2) "body should contain at least two functions")
(letfn [(prepend-chan-args
[orig new-args]
(let [orig-list (if (list? orig) orig (list orig))
fun-name (list (first orig-list))
fun-args (rest orig-list)]
(concat fun-name new-args fun-args)))]
(let [sz (count body)
num-chans (dec sz)
chan-syms (repeatedly num-chans gensym)
first-chan (first chan-syms)
last-chan (last chan-syms)
internal-chan-args (partition 2 1 chan-syms)
all-chan-args (concat `((~first-chan)) internal-chan-args `((~last-chan)))
body-exp (map prepend-chan-args body all-chan-args)
bind-exp (concat bindings (mapcat list chan-syms (repeat sz `(chan))))]
`(let [~@bind-exp]
~@body-exp))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment