A bit of Clojure magic and high order functions are served


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

About these ads

5 pensieri su “A bit of Clojure magic and high order functions are served

    • Hi guys, thanks for the reply.
      Partial is not exactly the way to go, for one simple reason: with partial you have to not specify correctly the “signature” of the function, since you can’t pass to a “partialized” function a number of argument < of expected ones: Example:

      (defn sum [a b] (partial + a)) ;; <- it will give you error invoking (sum 1) !!

      The only way to go are the two depicted in your posts, but there is one big drawback: who read your code can't be sure of which are the signatures of how use your functions. The worst thing is that you have defined a function using a def, which must be used (in idiomatic coding) only for specify binding with variable.
      My solution is cleaner, because you can specify the correct signature.
      Hope this help :)
      Alfredo

  1. > but really you will need to create n-arity high order function

    For example like map? map is exactly a n-arity higher order function.
    A higher order function is a function which takes a function as a parameter or returns a function. In this sense, currying is related with higher order functions (because when you pass just some parameters you are returning a function); however, the concepts are separate.

    map is a higher order function because its first argument is a function. And takes an arbitrary number of arguments.

    Automatic currying is nice to have (in Haskell). But the whole language is built around that concept. Besides, it leads in the direction of point(less)free programming, which I believe is quite less readable than lisp. I commented about that here.

    I would like to point out a few problems with /implicit/ currying in Clojure; perhaps later. ;)
    Time to eat!

    • Hi rik0! How are you? (Maybe you are going to tell me that in a private email hehe ).
      About currying and Clojure, I’m agree with you about the fact that is nice to have in Haskell because the whole language is build around it. Btw, I working on a clojure 3D Library (mail me if you are curious) which uses a FL-derived language developed by my professor. In this scenario, it’s extremely useful to have partial-applicable functions. I don’t know if it’s a good idea to have automatic-currying in everyday-Clojure-coding :)
      Bye,
      Alfredo

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...