## Wednesday, 31 October 2012

### Flipping Out

The next exercise is No. 46, Flipping Out: to write a higher-order function that flips the order of the arguments of an input function.  the lesson today is how to define a function when you do not know how many arguments it will be passed when it is called.

So I am writing a function flip-out that takes a function f as argument and returns a new function...

(def flip-out
(fn [f]...

What does is new function supposed to do when I call it?  If there are no arguments, it returns whatever the starting function would have returned:

([] (f))

No, it doesn't return the function we started with , which would be:

([] f)

...it calls said function and returns the result:

([] (f))

If the new function is called with one argument x then call the function with that argument:

([x] (f x))

If it is called with two arguments x and y then call the function with these arguments but in the other order as per the spec:

([x y] (f y x))

And finally if there are more than two argument our parameter list looks like this: the first argument x, the second argument y, and then a sequence of the remaining arguments conventionally labelled more:

[x y & more]

So we rebuild the argument list and reverse it:

(reverse (cons x (cons y more)))

...and apply our original function to the result. There is a higher-order function that does this, coincidentally called apply.  For example:

user=> (+ 1 2 3 4)
10
user=> (apply + '(1 2 3 4)) ; same thing
10

So we use apply thus:

(apply f (reverse (cons x (cons y more))))

So the whole function looks like this:

(def flip-out
(fn [f]
(fn
([] (f))
([x] (f x))
([x y] (f y x))
([x y & more] (apply f (reverse (cons x (cons y more))))))))

This defines the result as a function for testing.  To stick this into the 4Clojure page we need just the bit inside the definition.