Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reorder function arguments in Lisp

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?

like image 845
Nick Alger Avatar asked Oct 31 '25 13:10

Nick Alger


2 Answers

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.

like image 107
Rainer Joswig Avatar answered Nov 04 '25 02:11

Rainer Joswig


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


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!