Insertion into a list doesn't reflect outside function whereas deletion does?

87 Views Asked by At

I am new to Lisp. Deletion of an item in a list by a function gets reflected outside the function but insertion doesn't. How can I do the same for insertion?

For example

(defun test (a b)
  (delete 1 a)
  (delete 5 b)
  (append '(5) b)
  (member '5 b))

(setq x '(2 3 1 4))
(setq y '(8 7 5 3))

(test x y)

;;x and y after function ends
x
(2 3 4)
y
(8 7 3)

Why doesn't append affect list y? How can I insert something into y from within the function?

1

There are 1 best solutions below

0
On BEST ANSWER

Append isn't supposed to modify anything

Why doesn't append affect list y?

The first sentence of the documentation on append is (emphasis added):

append returns a new list that is the concatenation of the copies.

No one ever said that append is supposed to modify a list.

You can't change the value of a lexical binding outside its scope

How can I insert something into y from within the function?

In the most general sense, you cannot. What happens if the value of y is the empty list? There's no way with a function (as opposed to a macro) to make something like this work in Common Lisp:

(let ((list '())
  (insert list 1)
  l)
;=> (1)

A function cannot change the lexical binding of a variable outside its scope1, so there's no way for insert to change the value of list.

You can, of course, modify the internal structure of an object, so if the value of list is some non-empty list, then you could modify the structure of that list. The value of list wouldn't change (i.e., it would still the same cons cell), but the list represented by that cons cell would change. E.g.,

(defun prepend (list element)
  (let ((x (first list)))
    (setf (rest list) (list* x (rest list))
          (first list) element)))

(let ((list (list 1 2)))
  (prepend list 'a)
  list)
;=> (a 1 2)

Save return values

In general, you need to get into the habit of saving the results of functions. Most functions won't modify their arguments, so you need to save their results. Some functions are permitted, but not required, to modify their arguments, and they don't have to modify in a predictable way, so you need to save their results too. E.g., your code could be:

(defun test (a b)
  (setf a (delete 1 a))
  (setf b (delete 5 b))
  (setf b (append '(5) b))
  (member 5 b))

(test ...)
;=> true

1 You could work around this by giving it a setter function that closed over the binding, etc. But those kind of techniques would be workarounds.