--- title: Clojure auto curry date: 2021-04-24 layout: post lang: en ref: clojure-auto-curry --- A simple macro defined by [Loretta He][lorettahe] to create Clojure functions that are curried on all arguments, relying on Clojure's multi-arity support: ```clojure (defmacro defcurry [fname args & body] (let [partials (map (fn [n] `(~(subvec args 0 n) (partial ~fname ~@(take n args)))) (range 1 (count args)))] `(defn ~fname (~args ~@body) ~@partials))) ``` A naive `add` definition, alongside its usage and macroexpansion: ```clojure user=> (defcurry add [a b c d e] (+ 1 2 3 4 5)) #'user/add user=> (add 1) #object[clojure.core$partial$fn__5857 0x2c708440 "clojure.core$partial$fn__5857@2c708440"] user=> (add 1 2 3 4) #object[clojure.core$partial$fn__5863 0xf4c0e4e "clojure.core$partial$fn__5863@f4c0e4e"] user=> ((add 1) 2 3 4 5) 15 user=> (((add 1) 2 3) 4 5) 15 user=> (use 'clojure.pprint) nil user=> (pprint (macroexpand '(defcurry add [a b c d e] (+ 1 2 3 4 5)))) (def add (clojure.core/fn ([a b c d e] (+ 1 2 3 4 5)) ([a] (clojure.core/partial add a)) ([a b] (clojure.core/partial add a b)) ([a b c] (clojure.core/partial add a b c)) ([a b c d] (clojure.core/partial add a b c d)))) nil ``` This simplistic `defcurry` definition doesn't support optional parameters, multi-arity, `&` rest arguments, docstrings, etc., but it could certainly evolve to do so. I like how `defcurry` is so short, and abdicates the responsability of doing the multi-arity logic to Clojure's built-in multi-arity support. Simple and elegant. Same Clojure as before, now with auto-currying via macros. [lorettahe]: http://lorettahe.github.io/clojure/2016/09/22/clojure-auto-curry