LISP function affecting other function [duplicate]

2019-09-03 16:22发布

This question already has an answer here:

I noticed that when I call the function fillBoard, it seems to work as it fills the list passed to it as I want, but it has a very weird side effect. Somehow once fillBoard is called, the clearBoard function will only return the list returned by fillBoard. Additionally if I call fillBoard again it will continue to update the value returned in clearBoard.

As far as I understand, there should be a new instance of the list variable in clear everytime its called, so I don't see how its being modified or how its storing a new value.

I am passing fillBoard an empty list like ((0 0 0 0) (0 0 0 0) (0 0 0 0) (0 0 0 0)), and it will return a list like ((1 2 3 0) (0 6 0 0) (0 0 0 0) (0 0 0 0)), which is then what clearBoard returns.

(defun fillBoard (list)

   (let ((numVals (+ 4 (random 3)))
         (rand 0)
     (val1 0)
     (val2 0))

     (dotimes (x numVals)

     (setf val1 (random 3))
     (setf val2 (random 3))
     (setf rand (nth val1 (nth val2 soln)))

     (prin1 rand)
     (write-line " ")


     (if (= (nth val1 (nth val2 list)) 0)
     (setf (nth val1 (nth val2 list)) rand)))
      list))



(defun clearboard ()
   (let (( list '((0 0 0 0) (0 0 0 0) (0 0 0 0) (0 0 0 0))))
    list))

EDIT: I did seem to alleviate the issue by having clearBoard be passed a list then setting it directly to the blank board as opposed to a local variable, then returning that instead. However, I am still curious as to how what was happening in the original issue

2条回答
SAY GOODBYE
2楼-- · 2019-09-03 16:41

The list returned by clearboard is defined as a constant structure. When you modify it in fillBoard, you are not modifying a copy, but the structure itself. Generate the board instead with

(loop repeat 4 collect (make-list 4 :initial-element 0))
查看更多
萌系小妹纸
3楼-- · 2019-09-03 17:02

EQness of your return result

Your function returns the same literal list all the time. It is data embedded into your code. Don't modify it.

CL-USER 4 > (eq (clearboard) (clearboard))
T

EQ returns T, because the first cons in both lists is actually the same cons.

Allocate fresh new lists

Use COPY-TREE inside clearboard to create a newly allocated list of lists, instead of returning the same literal list over and over:

(defun clearboard ()
  (copy-tree '((0 0 0 0)
               (0 0 0 0)
               (0 0 0 0)
               (0 0 0 0))))


CL-USER 5 > (eq (clearboard) (clearboard))
NIL

Don't modify literal data

Literal data here is a data list, which is embedded in your code. Don't modify your code.

查看更多
登录 后发表回答