4

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
  • Your function f is not of n variables. It is called in your example as a single argument function. Commented Oct 23, 2010 at 10:21
  • The way I set it up i guess you're right, it takes a list as an argument. One would call it as follows, (f (x y z w)) I'm not stuck on calling it that way, something that swaps the literal arguments, eg (f x y z w) -> (f z y x w) would be good as well. Commented Oct 23, 2010 at 10:32
  • if X is a function, you can call it like that. If not, you get an error. Commented Oct 23, 2010 at 10:34

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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).
@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.
2

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.