Define a syntax error in Lisp function - lisp

I am bad at Lisp. Help me please to find a syntax error. I need to write a function which swaps two elements in list. This function must consist loop-cycle. Here is what if have so far.
(defun swap-two-element(z x y)
(let ((newlist nil) (newlist2 nil) (copyz z) (copyz2 z) (newx nil))
(loop
(when (= (- (length z) (length copyz2)) y)
(return (set newx car z)))
(setq newlist2 (append newlist2(car copyz2))
copyz2 (cdr copyz2)))))
Call example: (swap-two-element '(a b c d) 2 3)

Replace the word set with the word values and you are good to go.
PS. You need to address the warnings though, and explain what the function is supposed to do so that we could help you with the algorithm.

You really need to tidy up your question. The title says nothing, the code is badly formatted and you really need to play around with loop to get started. I won't give you your solution since you need to learn this by trying. Here is an example you can make use of to do your assignment.
;; this orders a list by their odd index
;; NB: index starts at zero so first element is even
(defun order-odd-index (list)
(loop :for element :in list ; iterates your list
:for index :from 0 ; starts from 0 and goes on
:if (oddp index) ; if in a loop
:collect element :into odd-list ; variable is automatically created
:else ; else in a loop
:collect element :into even-list
:finally (return (append odd-list even-list)))) ; what to do in the end
(order-odd-index '(4 67 3 2 7 9)) ; ==> (67 2 9 4 3 7)
I use keywords (like :for instead of for) to indicate what symbols are loop keywords and what are not. It's optional but I think it looks a lot cleaner.
Now your problem can be solved with collecting element into 5 variables. Two of them is when index is equal to one of the places (given as arguments) to be switched the other 3 are before, in between and greater. In the finally you can just append those variables in the correct order and you're done.

Related

lisp: chunking a vector

As mentioned here, I'm trying to teach myself lisp by implementing lodash.
I have basically no experience with lisp, so work that would be trivial in js is foreign to me.
For instance, I'm working on implementation of a _.chunk method, which in js takes an array and a size variable and 'chunks' the array by the size:
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
As somebody totally new to common lisp data types, I would assume that the analogous type would be a vector, not an array, is that correct?
Secondly, my way of solving this algorithmically would be to retain a length variable, and a pointer variable, and to grab a subset of the array/vector, [pointer to pointer + size], while pointer + size was < length, and then return [pointer to length] when that was no longer true, and incrementing pointer to pointer + size + 1 otherwise.
No idea how to implement this in lisp, here is my code so far.
(defun _.chunk (vector &optional (size 1 size-p))
(if (or (not size-p) (eq size 1))
vector
((let (
(array_length (array-total-size array))
(pointer)
)
???
))
)
)
For this implementation I would first write an idiomatic Common Lisp version of chunk that can be useful in a CL program (efficient, etc.), and then write a thin lodash layer that only wraps around those functions.
For example, I would first write a helper function to allow sharing storage with the chunked vector. A displaced array refers to another array but with an offset and different size. It may be useful to have chunks be only views of the original vector, so that they all share the same underlying storage array. It is not only a memory optimization: the behaviour is different when mutating either a chunk or the original vector, since any change in one is visible in the other. But as far as I know lodash is (was?) a pure functional language, so it makes sense to share some data if you don't mutate them. Some languages call those kind of indirect arrays "slices".
(defun slice (vector start end)
(make-array (- end start)
:element-type (array-element-type vector)
:displaced-to vector
:displaced-index-offset start))
So I would also make chunk-vector accept :start and :end parameters, as commonly done, along with sharedp which specifies if storage should be shared with the original vector:
(defun chunk-vector (size vector &key start end sharedp)
(check-type size (integer 1))
(loop
with slicer = (if sharedp #'slice #'subseq)
and low = (or start 0)
and high = (or end (length vector))
for s from low below high by size
for e from (+ low size) by size
collect (funcall slicer vector s (min e high))))
Note: I assume nil is a possible value for end that means the end of the vector, to mirror how subseq works. I do the same for start, because for those variables the nil value can be used without ambiguity to mean "default value". I could also have defined defaults in the lambda list, as done in tfb's answer.
Here are some tests:
(chunk-vector 3 #(0 1 2 3 4 5 6 7 8 9) :sharedp t)
(#(0 1 2) #(3 4 5) #(6 7 8) #(9))
(chunk-vector 2 #(0 1 2 3 4 5 6 7 8 9))
(#(0 1) #(2 3) #(4 5) #(6 7) #(8 9))
(chunk-vector 1 #(0 1 2 3 4 5 6 7 8 9))
(#(0) #(1) #(2) #(3) #(4) #(5) #(6) #(7) #(8) #(9))
Likewise, you could also define a chunk-list function and have the lodash chunck function dispatch to each specialized version based on the sequence type.
This can be done with CLOS, but since that is already demonstrated in another answer, I'll just define individual specialized functions.
Here is an implementation of chunk-list that is based on LDIFF.
I tried first mixing all cases in one function, but this becomes needlessly complex.
Here is first an unbounded chunk function:
(defun chunk-list/unbounded (size list)
(loop
for front = list then next
for next = (nthcdr size front)
collect (ldiff front next)
while next))
front is defined as initially list, then the current value of next at each step
next is the next chunk, computed using size; this plays nicely with lists that have not enough elements, since in that case nthcdr just returns the remaining elements.
A bit more complex case is required to handle the end argument, and for that we define the bounded version where there is also an additional upper-limit counter, that decreases by size at each step of iteration. It represents remaining number of elements to add, and is used along with size to compute (min size upper-limit), the size of the next chunk:
(defun chunk-list/bounded (size list upper-limit)
(loop
for front = list then next
for next = (nthcdr (min size upper-limit) front)
collect (ldiff front next)
do (decf upper-limit size)
while (and next (plusp upper-limit))))
Finally, chunk-list dispatches on both versions based on whether end is nil or not; the calls are inlined here (because we can):
(defun chunk-list (size list &key (start 0) end)
(declare (inline check-list/bounded check-list/simple))
(check-type size (integer 1))
(let ((list (nthcdr start list)))
(when list
(if end
(chunk-list/bounded size list (- end start))
(chunk-list/unbounded size list)))))
Some examples:
(chunk-list 3 '(1 2 3 4 5 6 7))
((1 2 3) (4 5 6) (7))
(chunk-list 29 '(1 2))
((1 2))
(chunk-list 2 (alexandria:iota 100 :start 0) :start 10 :end 20)
((10 11) (12 13) (14 15) (16 17) (18 19))
i would propose step-by step slicing iterating over the chunk index (since you can easily find out the total amount of chunks), using dotimes.
this could look something like the following:
(defun chunked (seq size)
(let* ((total (length seq))
(amount (ceiling total size))
(res (make-array amount :fill-pointer 0)))
(dotimes (i amount res)
(vector-push (subseq seq (* i size) (min (* (1+ i) size) total))
res))))
CL-USER> (chunked "abcdefgh" 3)
;; #("abc" "def" "gh")
CL-USER> (chunked #*00101 2)
;; #(#*00 #*10 #*1)
CL-USER> (chunked (list :a :b :c :d :e) 1)
;; #((:A) (:B) (:C) (:D) (:E))
CL-USER> (chunked (list :a :b :c :d :e) 4)
;; #((:A :B :C :D) (:E))
This is an addendum to coredump's answer, as well as referring to a comment by Kaz. Most of this is about style, which is always a matter of opinion and I do not claim my opinion is better than theirs: I just think it is interesting to talk about the choices as Lisp programming is very much about style choice, since the language is so flexible compared to most others. The last section ('extending') might be interesting however.
Argument order
The problem with a signature which is (size vector ...) is that size can't be optional. If you want it to be, it can't be the first argument to the function. Whether that outweighs the easy utility of partial-application libraries I don't know (however, in the 'do the right thing' spirit, if I wrote a partial application library it would allow you to specify which args it was currying, so this would not be a problem).
So if size needs to be optional then the argument order must be (vector size ...).
Further, since coredump's answer uses keyword arguments, I would make size be one as well as you almost never want to mix keyword & optional arguments. So that leads to a signature which would be (vector &key size start end sharedp), and I'd then write the actual function as
(defun chunk-vector (vector &key (size 1) (start 0) (end (length vector))
(sharedp nil))
(check-type size (integer 1))
(let ((slicer (if sharedp #'slice #'subseq)))
(loop for s from start below end by size
for e from (+ start size) by size
collect (funcall slicer thing s (min e end)))))
This slightly improves on coredump's version by defaulting the arguments in the arglist rather than later.
Extending chunk-vector
Pretty obviously you might want to chunk other kinds of things, such as lists, and pretty obviously the algorithm for chunking a list will be very different than that for chunking a vector, because you really do not want to repeatedly call subseq on a list.
Well, this is what CLOS is for. First of all we can define a generic chunk function:
(defgeneric chunk (thing &key)
;; in real life we might want to specify some of the keyword
;; arguments at the GF level, but we won't
)
And now define methods for classes we care about. Firstly the method to chunk vectors, which is pretty much the previous function:
(defmethod chunk ((thing vector) &key
(size 1) (start 0) (end (length thing)) (sharedp nil))
(check-type size (integer 1))
(let ((slicer (if sharedp #'slice #'subseq)))
(loop for s from start below end by size
for e from (+ start size) by size
collect (funcall slicer thing s (min e end)))))
And now, for instance, one to chunk lists. Note this may be buggy, and there may be better ways of doing this.
(defmethod chunk ((thing list) &key
(size 1) (start 0) (end nil endp) (sharedp nil))
;; This does not implemenent SHAREDP: this could only be useful for
;; the last chunk, and since you don't know if you could share a
;; chunk until you have already walked the list it did not seem
;; worth it. It may also be buggy in its handling of END.
(declare (ignorable sharedp))
(flet ((next (lt)
(nthcdr size lt))
(the-chunk (lt p)
(loop for c below (if endp (min size (- end p)) size)
for e in lt
do (print c)
collect e)))
(loop for tail on (nthcdr start thing) by #'next
for pos upfrom start by size
while (or (not endp) (< pos end))
collect (the-chunk tail pos))))
And of course you can now define methods on this function for other appropriate types.
The input could certainly be a vector (a vector is a 1-dimensional array). Lisp has a few more sensible options of how to represent the result: it could be a 2-dimensional array, a vector of vectors, or maybe even a list of vectors.
To get a 2-dimensional array:
(defun reshape-2d (column-count vector &optional padding-element)
(let* ((row-count (ceiling (length vector) column-count))
(array (make-array (list row-count column-count)
:initial-element padding-element)))
(loop :for i :below (length vector)
:do (setf (row-major-aref array i) (aref vector i)))
array))
To get a vector of vectors:
(defun chunkv (size vector)
(let ((vectors (make-array (ceiling (length vector) size))))
(loop :for i :below (length vector) :by size
:for j :below (length vectors)
:do (setf (aref vectors j) (subseq vector
i
(min (1- (length vector))
(+ i size)))))
vectors))
To get a list of vectors:
(defun chunkl (size vector)
(loop :for i :below (length vector) :by size
:collect (subseq vector
i
(min (1- (length vector))
(+ i size)))))
This last version could actually chunk any sequence because it only uses sequence functions.

Using Lisp: define a function that takes a list and a number and returns true if the number occurs in the list

I am new to lisp and I have a problem, I'm trying to find the number in the list but it is not working. I haven't made the return statement yet
(defun num (x 'y)
(if (member x '(y)) 't nil))
(write (num 10 '(5 10 15 20)))
My output just outputs the nil instead of doing the function and I'm confused of what I am doing wrong.
Solution
(defun member-p (element list)
"Return T if the object is present in the list"
(not (null (member element list))))
The not/null pattern is equivalent to (if (member element list) t nil) but is more common.
In fact, you do not really need this separate function,
member is good enough.
The -p suffix stands for predicate, cf. integerp and upper-case-p.
Your code
You cannot quote lambda list elements, so you need to replace defun num (x 'y) with defun num (x y)
You need not quote t
Quoting '(y) makes no sense, replace it with y.
You do not need to write the function call, the REPL will do it for you.
See also
When to use ' (or quote) in Lisp?
Can you program without REPL on Lisp?
You are almost certainly expected to not just use member, but to write a function which does what you need (obviously in real life you would just use member because that's what it's for).
So. To know if an object is in a list:
if the list is empty it's not;
if the head of the list is equal to the object it is;
otherwise it is in the list if it's in the tail of the list.
And you turn this into a function very straightforwardly:
(defun num-in-list-p (n l)
;; is N in L: N is assumed to be a number, L a list of numbers
(cond ((null l)
nil)
((= n (first l))
t)
(t
(num-in-list-p n (rest l)))))
You could use the built in position function which will return the index of the number if it is in the list:
(position 1 '(5 4 3 2 1))
If you want to define your own function:
CL-USER> (defun our-member(obj lst)
(if(zerop (length lst))
nil
(if(equal(car lst)obj)
T
(our-member obj (cdr lst)))))
OUR-MEMBER
CL-USER> (our-member 1 '(5 4 3 2 1))
T
CL-USER> (our-member 99 '(1 2 3 4 5))
NIL
We can create a function called "our-member" that will take an object (in your case a number) and a list (in your case a list of numbers) as an argument. In this situation our "base-case" will be whether or not the length of the list is equal to zero. If it is and we still haven't found a match, we will return nil. Otherwise, we will check to see if the car of the list (the first element in the list) is equal to the obj that we passed. If so, we will return T (true). However, if it is not, we will call the function again passing the object and the cdr of the list (everything after the car of the list) to the function again, until there are no items left within the list. As you can see, The first example of a call to this function returns T, and the second example call returns NIL.
What makes this utility function a good example is that it essentially shows you the under workings of the member function as well and what is going on inside.

function (OccurencesOfPrimes < list >) which counts the number of primes in a (possibly nested) list

I am working on problem to get the occurence of Prime in a list in lisp.
Input:
Write a function (OccurencesOfPrimes < list >) which counts the number of primes in a (possibly nested) list.
Output: Example: (OccurencesOfPrimes (((1)(2))(5)(3)((8)3)) returns 4.
I am using the below code but getting the error like:
(
defun OccurencesOfPrimes (list)
(loop for i from 2 to 100
do ( setq isPrime t)
(loop for j from 2 to i
never (zerop (mod i j))
(setq isPrime f)
(break)
)
)
(if (setq isPrime t)
(append list i)
)
)
)
LOOP: illegal syntax near (SETQ ISPRIME F) in
(LOOP FOR J FROM 2 TO I NEVER (ZEROP (MOD I J)) (SETQ ISPRIME F) (BREAK)
)
Any help.
It is important to keep the format consistent with the expected conventions of the language. It helps when reading the code (in particular with other programmers), and can help you see errors.
Also, you should use an editor which, at the minimum, keep tracks of parentheses. In Emacs, when you put the cursor in the first opening parenthesis, the matching parenthesis is highlighted. You can spot that you have one additional parenthesis that serves no purpose.
(
defun OccurencesOfPrimes (list)
(loop for i from 2 to 100
do ( setq isPrime t)
(loop for j from 2 to i
never (zerop (mod i j))
(setq isPrime f)
(break)
)
)
(if (setq isPrime t)
(append list i)
)
) ;; <- end of defun
) ;; <- closes nothing
In Lisp, parentheses are for the computer, whereas indentation is for humans. Tools can automatically indent the code according to the structure (the parenthesis), and any discrepancy between what indentation you expect and the one being computed is a hint that your code is badly formed. If you look at the indentation of your expressions, you can see how deep you are in the form, and that alone helps you understand the code.
Symbol names are dash-separated, not camlCased.
Your code, with remarks:
(defun occurences-of-primes (list)
;; You argument is likely to be a LIST, given its name and the way
;; you call APPEND below. But you never iterate over the list. This
;; is suspicious.
(loop
for i from 2 to 100
do
(setq is-prime t) ;; setting an undeclared variable
(loop
for j from 2 to i
never (zerop (mod i j))
;; the following two forms are not expected here according
;; to LOOP's grammar; setting IS-PRIME to F, but F is not
;; an existing variable. If you want to set to false, use
;; NIL instead.
(setq is-prime f)
;; BREAK enters the debugger, maybe you wanted to use
;; LOOP-FINISH instead, but the NEVER clause above should
;; already be enough to exit the loop as soon as its
;; sub-expression evaluates to NIL.
(break)))
;; The return value of (SETQ X V) is V, so here your test would
;; always succeed.
(if (setq is-prime t)
;; Append RETURNS a new list, without modifying its
;; arguments. In particular, LIST is not modified. Note that "I"
;; is unknown at this point, because the bindings effective
;; inside the LOOP are not visible in this scope. Besides, "I"
;; is a number, not a list.
(append list i)))
Original question
Write one function which counts all the occurrences of a prime number in a (possibly nested) list.
Even though the homework questions says "write one function", it does not say that you should write one big function that compute everything at once. You could write one such big function, but if you split your problem into sub-problems, you will end with different auxiliary functions, which:
are simpler to understand (they do one thing)
can be reused to build other functions
The sub-problems are, for example: how to determine if a number is a prime? how to iterate over a tree (a.k.a. a possibly nested list)? how to count
the occurrences?
The basic idea is to write an "is-prime" function, iterate over the tree and call "is-prime" on each element; if the element is prime and was never seen before, add 1 to a counter, local to your function.
You can also flatten the input tree, to obtain a list, then sort the resulting
list; you iterate over the list while keeping track of the last
value seen: if the value is the same as the previous one, you
already know if the number is prime; if the previous number differs, then
you have to test if the number is prime first.
You could also abstract things a little more, and define a higher-order tree-walker function, which calls a function on each leaf of the tree. And write another higher-order function which "memoizes" calls: it wraps around a
function F so that if you call F with the same arguments as before,
it returns the result that was stored instead of recomputing it.
Example
I'll combine the above ideas because if you give that answer to a teacher you are likely to have to carefully explain what each part does (and if you can, great for you); this is not necessarily the "best" answer, but it covers a lot of things.
(defun tree-walk-leaves (tree function)
(typecase tree
(null nil)
(cons
(tree-walk-leaves (car tree) function)
(tree-walk-leaves (cdr tree) function))
(t (funcall function tree))))
(defun flatten (tree &optional keep-order-p)
(let ((flat nil))
(tree-walk-leaves tree (lambda (leaf) (push leaf flat)))
(if keep-order-p
(nreverse flat)
flat)))
(defun prime-p (n)
(or (= n 2)
(and (> n 2)
(oddp n)
(loop
for d from 3 upto (isqrt n) by 2
never (zerop (mod n d))))))
(defun count-occurences-of-prime (tree)
(count-if #'prime-p (remove-duplicates (flatten tree))))
(count-occurences-of-prime '(((1)(2))(5)(3)((8)3)))
=> 4
If, instead, you don't want to remove duplicates but count the multiple times a prime number occurs, you can do:
(count-if (memoize #'prime-p) (flatten tree))
... where memoize is:
(defun memoize (function &key (test #'equalp) (key #'identity))
(let ((hash (make-hash-table :test test)))
(lambda (&rest args)
(let ((args (funcall key args)))
(multiple-value-bind (result exists-p) (gethash args hash)
(values-list
(if exists-p
result
(setf (gethash args hash)
(multiple-value-list (apply function args))))))))))
(memoize is useless if there are no duplicates)

DrRacket - Find Largest Number in a set

(for judges ([judge1 judge2 judge3 judge4 judge5 judge6 judge7 judge8])
(define i 0)
(define j 1)
(cond [(< judges[i] judges[j])
(cond [(equal? judges[j] judges(length))
(define highest-score judges[j])]
[else
(judges[i] judges[j])
(judges[j] judges[j +1])])]
[else
(cond [(equal? judges[i] judges[length -1])
(define highest-score judges[i])]
[else
(judges[j] judges[j +1])])]))
I want to be able to find the largest number in a set of values, which for this problem includes values from judge1, judge2... judge8. The way I'm trying to solve this problem is by taking the first two numbers on a list and comparing them; I can't seem to find much on DrRacket documentation on proper syntax for the type of operation I want to perform.
An easy way (in terms of writing code) to find the the maximum element is to sort the list, and grab the last element of that list. As #pdoherty926 mentioned, the easiest way to sort a list in Racket is with the sort function. You just give it a list and a comparitor, and it sorts the list for you:
> (sort '(5 2 6 1) <)
'(1 2 5 6)
And since you want the max value just grab the last element:
> (last (sort '(5 2 6 1) <))
6
Although if you want to find the maximum value of other (non-list) data structures, for is an attractive option. While your algorithm looks good, your syntax is off. In this particular case, I would actually recommend using for/fold. Basically, it lets you have an accumulator, which will hold your highest judge so far, as well as the list of judges you are iterating through, and the body for how you want to modify the accumulator. In this case, your loop will look something like:
;; A judge is a non-negative number
(define judges '(5 6 1 2))
(for/fold ([largest -1])
([j (in-list judges)])
...)
Where you replace the ... with the next value for largest. The entire loop evaluates to the final value for largest.
The interesting thing here is that j is an actual judge, not just an index to the judges list. So your body does not need to refer to the judges list at all. It should look something like:
(max j largest)
Since a judge is just a number. I will leave you to put the body in the loop as an exercise.
As an aside, since judges are just numbers, you can just use max directly with apply:
> (apply max '(5 6 1 2))
6
As one additional note, if for some reason you do want the actual index of the current judge you are examining, you can use in-naturals:
(for/fold ([largest -1])
([j (in-list judges)]
[index (in-naturals)])
...)
Following recursive function also works to find largest number in a list:
(define (largestnum slist)
(cond
((= (length slist) 2) ; if only 2 numbers, compare them
(if (> (car slist) (list-ref slist 1))
(car slist)
(list-ref slist 1)))
(else ; else recurse to compare car with largest of cdr
(let ((cdrLargest (largestnum (cdr slist))))
(if (> (car slist) cdrLargest)
(car slist)
cdrLargest)))))
(define judges '(5 6 1 2))
(largestnum judges)
Output:
6

What's the difference between (list nil) and '(nil) in Lisp? [duplicate]

This question already has answers here:
Why does this function return a different value every time?
(4 answers)
Unexpected persistence of data [duplicate]
(1 answer)
Closed 7 years ago.
First of all, let me say I'm a beginner in Lisp. To be honest I have been a beginner for some time now, but there are still many things I don't know well.
While I was writing this question, I came up with a strange bug in my code.
Here is a function that will return the list (0 1 ... n) with the list e appended. It uses rplacd along the way to keep track of the last element, to avoid a final call to last.
For example, (foo 4 '(x)) returns (0 1 2 3 4 x).
The "head" is stored in a, which is not simply nil, because there is only one nil, and never a copy of it (if I understand correctly), hence I can't simply append to nil.
(defun foo (n e)
(let* ((a (list nil)) (tail a))
(loop for i to n
do (rplacd tail (setf tail (list i)))
finally (rplacd tail (setf tail e))
(return (cdr a)))))
(defun bar (n e)
(let* ((a '(nil)) (tail a))
(loop for i to n
do (rplacd tail (setf tail (list i)))
finally (rplacd tail (setf tail e))
(return (cdr a)))))
The only difference between these functions is the (list nil) replaced by '(nil) in bar. While foo works as expected, bar always returns nil.
My initial guess is this happens because the original cdr of a is indeed nil, and the quoted list may be considered constant. However, if I do (setf x '(nil)) (rplacd x 1) I get (nil . 1) as expected, so I must be at least partially wrong.
When evaluated, '(nil) and (list nil) produce similar lists, but the former can be considered constant when present in source code. You should not perform any destructive operations on a constant quoted list in Common Lisp. See http://l1sp.org/cl/3.2.2.3 and http://l1sp.org/cl/quote. In particular, the latter says "The consequences are undefined if literal objects (including quoted objects) are destructively modified."
Quoted data is considered a constant. If you have two functions:
(defun test (&optional (arg '(0)))
(setf (car arg) (1+ (car arg)))
(car arg))
(defun test2 ()
'(0))
These are two functions both using the constant list (0) right?
The implementation may choose to not mutate constants:
(test) ; ==> Error, into the debugger we go
The implementation can cons the same list twice (the reader might do that for it)
(test2) ; ==> (0)
(test) ; ==> 1
(test) ; ==> 2
(test) ; ==> 3
(test2) ; ==> (0)
The implementation can see it's the same and hench save space:
(test2) ; ==> (0)
(test) ; ==> 1
(test) ; ==> 2
(test) ; ==> 3
(test2) ; ==> (3)
In fact. The last two behavior might happen in the same implementation dependent on the function being compiled or not.
In CLISP both functions work the same. I also see when disassembling with SBCL that the constant actually is mutated so I wonder if perhaps it has constant folded (cdr '(0)) at compile time and doesn't use the mutated list at all. It really doesn't matter since both are considered good "undefined" behavior.
The part from CLHS about this is very short
The consequences are undefined if literal objects (including quoted
objects) are destructively modified.