how to do value assignment issue in lisp

I am learning common lisp and tried to implement a swap value function to swap two variables' value. Why the following does not work?

(defun swap-value (a b)
           (setf tmp 0)
             (progn
              ((setf tmp a)
               (setf a b)
               (setf b tmp))))

Error info:

in: LAMBDA NIL
;     ((SETF TMP A) (SETF A B) (SETF B TMP))
; 
; caught ERROR:
;   illegal function call

;     (SB-INT:NAMED-LAMBDA SWAP-VALUE
;         (A B)

dfan is right, this isn't going to swap the two values.

The reason you are getting that error though is that this:

(progn
  ((setf tmp a)
   (setf a b)
   (setf b tmp)))

should be this:

(progn
  (setf tmp a)
  (setf a b)
  (setf b tmp))

The first progn has one s-expression in the body, and it's treated as an application of the function (setf tmp a). In Common Lisp, I think that only variables or lambda forms can be in the function position of an application. I could be wrong about the details here, but I know there are restrictions in CL that aren't in Scheme. That's why it's an illegal call.

For instance, this is illegal in CL and results in the same error:

CL-USER> ((if (< 1 2) #'+ #'*) 2 3)
; in: LAMBDA NIL
;     ((IF (< 1 2) #'+ #'*) 2 3)
; 
; caught ERROR:
;   illegal function call
; 
; compilation unit finished
;   caught 1 ERROR condition

You COULD write a swap as a macro (WARNING: I'm a Lisp noob, this might be a terrible reason for a macro and a poorly written one!)

(defmacro swap (a b)
  (let ((tmp (gensym)))
    `(progn
       (setf ,tmp ,a)
       (setf ,a ,b)
       (setf ,b ,tmp))))

Nope! Don't do this. Use rotatef as Terje Norderhaug points out.

7.1.2. Assignment, is the ``simple variable assignment statement'' of Lisp. Some programmers choose to avoid setq as a matter of style, always using setf for any kind (If several variables are to be assigned in parallel in the context of a loop, the do construct� When let is executed, each variable is assigned the respective value and lastly the s-expression is evaluated. The value of the last expression evaluated is returned. If you don't include an initial value for a variable, it is assigned to nil. Example. Create new source code file named main.lisp and type the following code in it.

You can use the ROTATEF macro to swap the values of two places. More generally, ROTATEF rotates the contents of all the places to the left. The contents of the leftmost place is put into the rightmost place. It can thus be used with more than two places.

Variables, Then I'll discuss Common Lisp's general-purpose assignment operator, SETF object references.5 Thus, you can assign a new value to a function parameter within For that matter, Algol programmers should also feel right at home, as Algol� For do*, the first step-form is evaluated, then the value is assigned to the first var, then the second step-form is evaluated, then the value is assigned to the second var, and so on; the assignment of values to variables is done sequentially, as if by setq.

A function (rather than macro) swapping two special variables can take the variable symbols as arguments. That is, you quote the symbols in the call. Below is an implementation of such a swap function:

(defvar *a* 1)
(defvar *b* 2)

(defun swap-values (sym1 sym2)
  (let ((tmp (symbol-value sym1)))
    (values
     (set sym1 (symbol-value sym2))
     (set sym2 tmp))))

? (swap-values '*a* '*b*) 
2
1

? *a*
2

Note the use of defvar to define global/special variables and the per convention use of earmuffs (the stars) in their names. The symbol-value function provides the value of a symbol, while set assigns a value to the symbol resulting from evaluating its first argument. The values is there to make the function return both values from the two set statements.

Successful Lisp, Any time your program invokes SETQ or SETF , it is assigning a new value to an existing Assignment can also cause problems when shared data is involved. The default value is 600. max-lisp-eval-depth provides another limit on depth of nesting. See section Eval. When a Variable is "Void" If you have never given a symbol any value as a global variable, we say that that symbol's global value is void. In other words, the symbol's value cell does not have any Lisp object in it.

You can not use setf to build a lexical variable tmp. You can use let, as follow:

 (defun swap-value (a b)
       (let ((tmp 0))
         (setf tmp a)
         (setf a b)
         (setf b tmp))
       (values a b))

which will do you hope.

LISP - Variables, LISP - Variables - In LISP, each variable is represented by a symbol. You can refer to the variable using the symbol itself as an expression. When let is executed, each variable is assigned the respective value and lastly the s- expression is� Sr.No. Function & Description; 1: read & optional input-stream eof-error-p eof-value recursive-p. It reads in the printed representation of a Lisp object from input-stream, builds a corresponding Lisp object, and returns the object.

Complimentary to other answers, the OP's targeted problem - the (multiple) value assignment issue - can be solved by parallel assignment using psetf:

(let ((a 21)
      (b 42))
  (psetf a b
         b a)
  (print (list a b)))
;; (42 21)

CLHS: Special Form SETQ, Assigns values to variables. (setq var1 form1 var2 form2 ) is the simple variable assignment statement of Lisp. First form1 is evaluated and the result is stored� Otherwise, the else-forms are evaluated in textual order, and the value of the last one is returned. (The else part of if is an example of an implicit progn. See Sequencing.) If condition has the value nil, and no else-forms are given, if returns nil. if is a special form because the branch that is not selected is never evaluated—it is ignored.

CS 161 Recitation Notes, Variables (or atoms as they are called in Lisp) are evaluated as their value if they are Now that I've demonstrated global assignment in Lisp, forget about it. or function that takes a list as an argument can be passed () with no problem. Default value: false. When setcheckbreak is true, Maxima will present a break prompt whenever a variable on the setcheck list is assigned a new value. The break occurs before the assignment is carried out. At this point, setval holds the value to which the variable is about to be assigned. Hence, one may assign a different value by assigning to

Using setq - Programming in Emacs Lisp, As a practical matter, you almost always quote the first argument to set . Also, setq can be used to assign different values to different variables. The first� Variables in Lisp are often called bindings; the variable, or name, is bound to a value. The variable cell is bound to the the cons cell (1 . 2). When we go into the inner let, we evaluate (car cell) to produce the value 1, which is then bound to the variable x. Then, we assign a new value, 3, to the variable x.

Translation of Pascal programs for execution on Lisp-based machines, problems arise from the radical differences in the control and data structures of the two to make direct use of a translated Lisp version of pro- grams written in 'PSETQ' and 'PSETF' perform assignments of values to symbols in parallel. The discussion concentrates on LISP implementations and points out why most current LISP systems are not as general as the original LISP 1.5 system. Readers not familiar with LISP should be able to read this paper without difficulty since we have tried to couch the argument in ALGOL-like terms as much as possible.

Comments
  • I don't know Common Lisp well enough to tell you why you are getting that error, but I can tell you that this will not swap the two variables' values even if you fix the error, because the arguments to swap-value are passed by value, so they won't affect the bindings outside the call; (swap-value x y) will pass in the values of x and y, having no effect on what x is bound to. To get the effect you want, you will have to write a macro.
  • Nice point. What surprised me there is I think setf is a global-wide assigner. I am still stuck in a C programmer's mindset. Anybody can elaborate Lisp's Way to do value assignment?
  • setf is the Lisp way to do value assignment, but it's not the way to introduce global variable. You should use defvar or defparameter for introducing global (and special, aka dynamic variables). This is a bit too complicated to explain in a comment, but check out Practical Common Lisp: gigamonkeys.com/book/variables.html
  • When coming to Common Lisp from more procedural languages, many tend to overuse setf for assignments. I suggest taking a moment when using setf to consider whether there are more idiomatic ways to implement the same functionality. Like using let to bind a local variable.
  • Why you don't suggest writing this macro? It looks alright.
  • Thanks a lot Terje~ You make the answer very complete and thorough now. Lispers are so kind~ Studying hard to be one of you guys~~
  • Thanks for this. It looks like -- if I use (setf tmp 0) outside the scope of 'progn, the tmp variable becomes global. I can inspect it under repl. But 'a and 'b is local. Anyone please correct me if I am wrong on this.. Using let is the right way, indeed.
  • Using setf on a symbol outside a scope binding a value to the symbol will indeed create a global variable. Some Common Lisp implementations may issue a warning about the variable not being declared.
  • In this specific case (take two values, return them in the reversed order, as two return values), it would probably be better to just use (defun swap-values (a b) (values b a)) Also note that neither my function nor @wislin 's function actually change state.