Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Higher-order functions in Clojure

Clojure is awesome, we all know this, but that's not the point. I'm wondering what the idiomatic way of creating and managing higher-order functions in a Haskell-like way is. In Clojure I can do the following:

(defn sum [a b] (+ a b)) 

But (sum 1) doesn't return a function: it causes an error. Of course, you can do something like this:

(defn sum   ([a] (partial + a))    ([a b] (+ a b))) 

In this case:

user=> (sum 1) #<core$partial$fn__3678 clojure.core$partial$fn__3678@1acaf0ed> user=> ((sum 1) 2) 3 

But it doesn't seem like the right way to proceed. Any ideas?
I'm not talking about implementing the sum function, I'm talking at a higher level of abstraction. Are there any idiomatic patterns to follow? Some macro? Is the best way defining a macro or are there alternative solutions?

like image 417
Alfredo Di Napoli Avatar asked Mar 16 '11 17:03

Alfredo Di Napoli


People also ask

What are higher order functions used for?

Higher order functions are functions that operate on other functions, either by taking them as arguments or by returning them. In simple words, A Higher-Order function is a function that receives a function as an argument or returns the function as output. For example, Array. prototype.

What does FN mean in Clojure?

First Class Functions They can be assigned as values, passed into functions, and returned from functions. It's common to see function definitions in Clojure using defn like (defn foo … ​) . However, this is just syntactic sugar for (def foo (fn … ​)) fn returns a function object.

What is the difference between callback and higher-order function?

Higher-Order Functions(HoF): A function that takes another function(s) as an argument(s) and/or returns a function as a value. Callback Functions(CB): A function that is passed to another function.

What are higher order functions how these functions are defined and used in functional programming?

Higher Order Function In functional programming, a function is defined as a "first order citizen". This means it includes all the properties generally available to any other element, such as the possibility of being affected to a name, returned as a result or passed as a parameter.


2 Answers

I've played a bit with the functions suggested by amalloy. I don't like the explicit specification of the number of argument to curry on. So I've created my custom macro. This is the old way to specific an high order function:

(defn-decorated old-sum   [(curry* 3)]   [a b c]   (+ a b c)) 

This is my new 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))) 

And this is the new implicit way:

(defn-ho new-sum [a b c] (+ a b c)) 

As you can see there is no trace of (curry) and other stuff, just define your currified function as before.

Guys, what do you think? Ideas? Suggestions? Bye!

Alfedo

Edit: I've modified the macro according the amalloy issue about docstring. This is the updated version:

(defmacro defhigh   "Like the original defn-decorated, but the number of argument to curry on   is implicit."   [fn-name & defn-stuff]   (let [[fst snd] (take 2 defn-stuff)          num-of-args (if (string? fst) (count snd) (count fst))]     `(defn-decorated ~fn-name [(curry* ~num-of-args)] ~@defn-stuff))) 

I don't like the if statement inside the second binding. Any ideas about making it more succint?

like image 40
Alfredo Di Napoli Avatar answered Oct 19 '22 11:10

Alfredo Di Napoli


Someone has already implememented this on the Clojure group. You can specify how many args a function has, and it will curry itself for you until it gets that many.

The reason this doesn't happen by default in Clojure is that we prefer variadic functions to auto-curried functions, I suppose.

like image 174
amalloy Avatar answered Oct 19 '22 11:10

amalloy