views:

69

answers:

2

I'm interested in an operator, "swap-arg", that takes as input 1) a function f of n variables, and 2) index k, and then returns a the same function except with the first and kth input variables swapped. eg (in mathematical notation):

(swap-arg(f,2))(x,y,z,w) = f(z,y,x,w)

Now my first idea is to implement this using rotatef as follows,

(defun swap-args (f k) 
  (lambda (L) (f (rotatef (nth k L) (car L)))))

However, this seems inelegant since it uses rotatef on the input. Also, it's O(n), and could be O(n^2) in practice if applied repeatedly to reindex everything.

This seems like a common problem people would have already considered, but I haven't been able to find anything. What's a good way to swap inputs like this? Is there a standard method people use?

+3  A: 

Using APPLY:

(defun create-swapped-arg-function (f k)
  "Takes as input a function f of n variables and an index k.
Returns returns a new function with the first and kth input variables swapped,
which calls the function f."
  (lambda (&rest args)
    (apply f (progn
                (rotatef (nth k args) (first args))
                args))))

Example:

CL-USER 5 > (funcall (create-swapped-arg-function #'list 2) 0 1 2 3 4 5 6)
(2 1 0 3 4 5 6)

Another way to do it would be to build the source code for such a function, compile it at runtime and return it. That would be useful if these functions are not created often, but called often.

Rainer Joswig
That's basically what I was trying to write in the OP, except without the bugs. (: The problem still remains though - it is O(N) due to the call to n'th, and also uses rotatef on the inputs which would change them (if I understand correctly).
mazemaster225
@mazemaster255: It would not change the inputs when called with FUNCALL. It might when called with APPLY. If you want to avoid that use COPY-LIST to create a new one. Sure it would be slow at runtime. See the last paragraph of my answer for an alternative.
Rainer Joswig
Ok, thanks for the help.
mazemaster225
+1  A: 

Just for completeness, functions can also take keyword (named) arguments, using this the function can be called with any order of its keyword arguments.

johanbev