Last active
December 13, 2015 21:28
-
-
Save CmdrDats/4977643 to your computer and use it in GitHub Desktop.
Non automatic currying to support variadic argument lists...
This file contains hidden or 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
;; 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