Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
like image 518
lkahtz Avatar asked Nov 29 '22 18:11

lkahtz


2 Answers

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.

like image 78
Terje Norderhaug Avatar answered Feb 08 '23 15:02

Terje Norderhaug


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.

like image 20
michiakig Avatar answered Feb 08 '23 15:02

michiakig