Skip to content

Instantly share code, notes, and snippets.

@CmdrDats
Last active December 13, 2015 21:28
Show Gist options
  • Save CmdrDats/4977643 to your computer and use it in GitHub Desktop.
Save CmdrDats/4977643 to your computer and use it in GitHub Desktop.
Non automatic currying to support variadic argument lists...
;; Some helper functions that adds support for currying-like syntax to function definitions but
;; still enable you to use variadic arguments in each function call.
(defn collect-vec
([l] (collect-vec l []))
([[h & t :as p] acc]
(cond
(not (vector? h)) [acc p]
(nil? t) [acc [h]]
:else
(recur t (conj acc h)))))
(defmacro defcurry
"Transforms (defcn f [x] [y] ...) to (defn f [x] (fn [y] ...))"
^{:arglists '([name doc-string? attr-map? [params*]+ body])}
[name op & [h & r :as opts]]
(let [[doc-string & [h & r :as opts]] (if (string? h) opts (cons "" opts))
[attr-map & [h & r :as opts]] (if (map? h) opts (cons {} opts))
[[fp & params] body-forms] (collect-vec opts)]
(loop [[p & ps] (reverse params)
body `(~op ~@body-forms)]
(cond
(nil? p)
`(defn ~name ~doc-string ~attr-map ~fp
~body)
:else
(recur ps `(fn ~p ~body))))))
(defmacro defcn
"Transforms (defcn f [x] [y] ...) to (defn f [x] (fn [y] ...))"
^{:arglists '([name doc-string? attr-map? [params*]+ body])}
[name & [h & r :as opts]]
`(defcurry ~name do ~@opts))
(defmacro defcnd
"Transforms (defcn f [x] [y] ...) to (defn f [x] (fn [y] ...))"
^{:arglists '([name doc-string? attr-map? [params*]+ body])}
[name & [h & r :as opts]]
`(defcurry ~name cond ~@opts))
;; Example usage :
(defcn f
"Function that adds"
[x & xs] [y & ys]
(apply + x y (concat xs ys)))
;; is identical to
(defn f
"Function that adds"
[x & xs]
(fn [y & ys]
(apply + x y (concat xs ys))))
;; Supports an arbitrary number of function levels :
(defcn f [x] [y] [z] [g] (g x y z))
((((f 1) 2) 3) +)
;; Example of defcnd (implicit cond)
(defcnd bucket [f] [& [a i]]
(nil? i) {}
:else
(update-in a [(f i)] #(conj %1 %2) i))
(reduce (bucket :cat) {} [{:cat "Home" :name "Fork"} {:cat "Work" :name "Laptop"} {:cat "Home" :name "Knife"}])
;; => {"Work" ({:name "Laptop", :cat "Work"}), "Home" ({:name "Knife", :cat "Home"} {:name "Fork", :cat "Home"})}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment