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.