First of all, if you are studying functional programming or Lisps in general, and not just Common Lisp, do not . Do not try to write functions that change state - this is not how functional programming works. If you need a function that changes 2 values, just write functions that return them in reverse order.
If you are still interested in exchanging 2 values, see this similar question for a few very good suggestions. The most important are macros and reference links (wrappers for actual values).
However, these answers do not include one important concept, available only in Common Lisp, and not in most other Lisp dialects - places . But first let me recall two ways to pass a variable to a function. Consider the following example in C ++:
void f(int x) { ... } int a = 5; f(a);
This is called a "move to value" strategy: the value of a copied to the parameter x . And since x is just a copy, if you change it inside f() , nothing will happen to the original variable a .
However, in C ++ you can also do the following:
void f(int& x) { ... } int a = 5; f(a);
This strategy is called "pass-by-reference" - here you pass a pointer to the location in memory where a is located. So x and a point to the same piece of memory, and if you change x , then t21 will also change.
Functional languages, including Common Lisp, do not allow variables to be passed to functions by reference. So how does setf work? It turns out that CL has the concept of place (sometimes also called "location"), which defines a location in memory, setf (a macro that is expanded to a special form set ), works directly with places, not values.
Summarizing:
- Generic Lisp, like most Lisps, only allows variables to be passed by function only by value .
- Lisp has the concept of places - a location in memory.
setf works directly with places and can be used to modify variables. Macros can be used to overcome feature limitations.
Note that some built-in functions in the CL may return places, for example. car , cdr , aref , as well as all object accessors. See these pages for some examples.
UPDATE
In your new question, you can change the values - inside the function by reference or outside without links. However, none of them would be correct in functional programming. The correct answer here is: do not change anything . In FP, you usually have state variables, but instead of changing them, you create a modified copy and pass it on so that the original variable does not change. Consider an example of a recursive function to calculate the factorial:
(defun factorial-ex (x accum) (if (<= x 1) accum (factorial-ex (- x 1) (* x accum)))) (defun factorial (x) (factorial-ex x 1))
factorial-ex is an auxiliary function that takes another parameter - the accumulator for the current state of calculation. For each recursion call, we decrease x by 1 and multiply accum by the current value of x . However, we do not change the x and accum - we pass the new values to the recursive function call. Physically, there are many copies of x and accum — one for each function call — and not one of them changes.
(Note that some CL implementations with certain parameters may use the so-called tail call optimization , which interrupts the statement about different places in the memory above, but at the moment you should not worry about that.)
In your task you can do the same. Instead of changing your 3 variables - inside or outside - make your modified copies and pass them to a recursive call. In imperative programming, you use variables and loops, and in functional programming, you should prefer fixed values and recursion.