user998509
user998509

Reputation: 23

Dolist evaluation error

I'm a CommonLisp noob with a question. I have these two functions below.

A helper function:

(defun make-rests (positions rhythm)
  "now make those positions negative numbers for rests"
  (let ((resultant-rhythm rhythm))
    (dolist (i positions resultant-rhythm)
      (setf (nth i resultant-rhythm) (* (nth i resultant-rhythm) -1)))))

And a main function:

(defun test-return-rhythms (rhythms)
  (let ((positions '((0 1) (0)))
        (result nil))
    (dolist (x positions (reverse result))
      (push (make-rests x rhythms) result))))

When I run (test-return-rhythms '(1/4 1/8)), it evaluates to: ((1/4 -1/8) (1/4 -1/8))

However, I expected: (test-return-rhythms '(1/4 1/8)) to evaluate to: ((-1/4 -1/8) (-1/4 1/8)).

What am I doing wrong?

Upvotes: 2

Views: 119

Answers (1)

danlei
danlei

Reputation: 14291

Your implementation of make-rests is destructive.

CL-USER> (defparameter *rhythm* '(1/4 1/4 1/4 1/4))
*RHYTHM*
CL-USER> (make-rests '(0 2) *rhythm*)
(-1/4 1/4 -1/4 1/4)
CL-USER> *rhythm*
(-1/4 1/4 -1/4 1/4)

So, if you run your test, the second iteration will see (-1/4 -1/8), and (make-rests '(0) '(-1/4 -1/8)) returns (1/4 -1/8). Your use of let in make-rests does not copy the list, it just creates a new binding that references it. Use copy-list in your let, or write a non-destructive version in the first place:

(defun make-rests (positions rhythm)
  (loop for note in rhythm
        for i from 0
        collect (if (member i positions) (* note -1) note)))

Upvotes: 1

Related Questions