Fennel wiki: Currying

Functions in functional languages like Haskell have a specific property of being able to be called with fewer arguments than required, producing another function partially supplementing specified arguments, and waiting for more. This process is called Currying. The snippet below shows how this can be achieved in Fennel with higher-order functions and a simple macro:

(fn curry [f n ?args]
  (let [args (or ?args {:n 0})]
    (fn [...]
      (let [inner (table.pack ...)
            n* (+ args.n inner.n)]
        (doto inner
          (table.move 1 inner.n (+ args.n 1))
          (tset :n n*))
        (table.move args 1 args.n 1 inner)
        (if (>= n* n)
            (f ((or _G.unpack table.unpack) inner 1 n*))
            (curry f n inner))))))

(macro defcurry [name arglist ...]
  `(local ,name
     (curry (fn ,arglist ,...)
            ,(length (icollect [_ a (ipairs arglist)
                                :until (= (tostring a) "...")]

The macro simply automates the process of figuring out the required argument amount for a function to work. For example:

>> (defcurry tri-plus [a b c]
     (+ a b c))
>> (tri-plus 1)
#<function: 0x55ada32d3430>
>> ((tri-plus 1) 2)
#<function: 0x55ada3232260>
>> (((tri-plus 1) 2) 3)
>> ((tri-plus 1 2) 3)
>> ((tri-plus 1) 2 3)

This macro supports variadic functions as well.