Question

I have a list that is used within a loop, and on each iteration I apply a function that will alter the list permanently (popping and adding elements). The problem is, the original list is never changed whenever it is nil. How may I solve this problem?. My code is shown below

(defun looping-func ()
    (let ((queue '(2)))
          (loop while (not (null queue)) do
            (let (  (num (pop queue)))
                (if (oddp num)
                    (format t "~%~A success" num)
                    (progn (format t "~%fail")
                           (add-to-list (1+ num) queue)))))))

(defun add-to-list (elem l)
    (nconc l (list elem)))

The code works as intended if the list contains more than 1 element. if it contains exactly 1 element, once that element is popped and the list becomes nil, the applied changes aren't permanent to the list anymore. I suppose this is because of how nconc is defined, if the first argument is nil, just return the second one without any alteration. Any ideas on how to go about this?

PS: I know the code above is useless, but I am using the same concept for a school project that I unfortunately can't post code for.

Was it helpful?

Solution

Change

(add-to-list (1+ num) queue)

to

(setq queue (add-to-list (1+ num) queue))

You can't "extend" nil with nconc

(nconc nil . lists)

is equivalent to

(nconc . lists)

so, you need to put the result of add-to-list in queue

OTHER TIPS

Don't add elements to the end of a list.

Never.

Lists in Lisp are designed in a way that adding an element to the head is cheap. Adding to the end is potentially costly.

To implement a LIFO queue you need a different implementation.

Don't alter constant literal data in source code during runtime.

Indent your code properly.

Because I assumed this to be an exercise, here's an example, which you shouldn't use in your daily practice, you should use push macro, which probably does something similar to it:

(defmacro push-example (item list)
  (let ((the-list list))                ; we do this to prevent
                                        ; multiple evaluations
                                        ; of the `list' argument
  `(setq ,the-list (cons ,item ,the-list))))

(defparameter *test* nil)

(push-example 'foo *test*) ;; (foo)
*test* ;; (foo)

While you didn't ask for a macro (you asked for the function), Doug's answer is technically more correct, this illustrates how you could have done it using code generation through macro. Notice how this is basically doing the same thing as your function does, except that it can encapsulate the call to setq you would have to make otherwise.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top