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.

No comments:

Post a Comment