Hi guys, what’s up?
I’m a little busy right now. I’ve started what is probably going to be my last semester of university courses and I’ve started coding a Clojure 3D library (coming soon on these screens). But this is the good time to take a break and write something on this blog. A really cool (and useful) features of Haskell is the ability to use High Order Functions. Take a look to this simple Haskell snippet:
> :t take take :: Int -> [a] -> [a] > :t take 10 take 10 :: [a] -> [a] > :t take 10 ['a'..'z'] take 10 (enumFromTo 'a' 'z') :: [Char]
As you can see the arguments are “eaten” one by one in a way that remember the dear old Pacman. In a nutshell take 10 returns a function that applied to a sequence return a result. Simple enough, isn’t it?
Unfortunately this doesn’t happens by default in Clojure. Observe this little function:
(defn sum [a b] (+ a b))
If you’ll try to invoke
(sum 1)
you we’ll get the following:
Wrong number of args (1) passed to: user$sum
This is absolutely normal, since it is the Clojure default behaviour. Googling and Stack-overflowing around a bit, I came up to a simple snippet to implement with a macro the required behaviour:
(defmacro defn-decorated "like defn except it accepts an additional vector of decorator functions which will be applied to the base definition. the decorators are applied in left-to-right order." {:author "Robert McIntyre" :arglists '[[name [modifers*] doc-string? attr-map? [params*] body] [name [modifers*] doc-string? attr-map? ([params*] body) + attr-map?]]} [fn-name decorators & defn-stuff] `(do (defn ~fn-name ~@defn-stuff) (alter-var-root (var ~fn-name) (reduce comp identity (reverse ~decorators))) (var ~fn-name))) (defn curry** [number-of-args f] (fn ([& args] (let [number-of-inputs (count args)] (if (= number-of-inputs number-of-args) (apply f args) (curry** (- number-of-args number-of-inputs) (apply (partial+ partial+ f) args))))))) (def curry* (curry** 2 curry**))
(By the way you can find the complete clj file here.) Here’s an example of application:
(defn-decorated sum [(curry 2)] [a b] (+ a b))
But a thing I didn’t like was the explicit passing of the number of argument which the function is composed, so I wrote my own macro:
(defmacro defn-ho [fn-name & defn-stuff] (let [number-of-args (count (first defn-stuff))] `(defn-decorated ~fn-name [(curry* ~number-of-args)] ~@defn-stuff)))
With this simple add-on, you can easily write any kind of high order function in a way like this:
(defn-ho new-sum [a b c] (+ a b c))
I haven’t tried it in particular situations (e.g. with destructuring) but don’t expect it to work with function with multiple arity: indeed, but really you will need to create n-arity high order function??
Feedback are welcome, as always!
Cheers!
Alfredo