From: Sean Winship
Subject: value not reinitialized on subsequent function calls
Date: 
Message-ID: <7bd2848c.0411301322.1fb0264c@posting.google.com>
I'm working my way through the problems in "Common Lisp: A Gentle
Introduction To Symbolic Computation" (available for download at
http://www-2.cs.cmu.edu/~dst/LispBook/index.html) and have run into some
behavior I don't understand.  Exercise 11.22(d) specifies a function for
counting DNA bases in a sequence.  My solution is:

(defun count-bases (strand)
  "Exercise 11.22(d) from Touretzky's 'Common Lisp'."
  (labels ((flatten (tree)
             (cond ((null tree) nil)
                   ((atom tree) (list tree))
                   (t (append (flatten (first tree)) (flatten (rest tree)))))))
    (let ((base-counts '((a 0) (c 0) (g 0) (t 0)))
          (single-strand (flatten strand)))
      (dolist (base single-strand base-counts)
        (incf (cadr (assoc base base-counts)))))))

When I run this function once, e.g.:

(count-bases '((g c) (a t) (t a) (t a) (c g)))

I get the correct answer.  When I run it again, the numbers accumulate:

((A 3) (C 2) (G 2) (T 3))
((A 6) (C 4) (G 4) (T 6))
((A 9) (C 6) (G 6) (T 9))
etc.

Why isn't base-counts being reinitialized each time?

Thanks for any help,

Sean

From: David Sletten
Subject: Re: value not reinitialized on subsequent function calls
Date: 
Message-ID: <8n6rd.29$Ew6.12@twister.socal.rr.com>
Sean Winship wrote:

> I'm working my way through the problems in "Common Lisp: A Gentle
> Introduction To Symbolic Computation" (available for download at
> http://www-2.cs.cmu.edu/~dst/LispBook/index.html) and have run into some
> behavior I don't understand.  Exercise 11.22(d) specifies a function for
> counting DNA bases in a sequence.  My solution is:
> 
> (defun count-bases (strand)
>   "Exercise 11.22(d) from Touretzky's 'Common Lisp'."
>   (labels ((flatten (tree)
>              (cond ((null tree) nil)
>                    ((atom tree) (list tree))
>                    (t (append (flatten (first tree)) (flatten (rest tree)))))))
>     (let ((base-counts '((a 0) (c 0) (g 0) (t 0)))
>           (single-strand (flatten strand)))
>       (dolist (base single-strand base-counts)
>         (incf (cadr (assoc base base-counts)))))))
> 
> When I run this function once, e.g.:
> 
> (count-bases '((g c) (a t) (t a) (t a) (c g)))
> 
> I get the correct answer.  When I run it again, the numbers accumulate:
> 
> ((A 3) (C 2) (G 2) (T 3))
> ((A 6) (C 4) (G 4) (T 6))
> ((A 9) (C 6) (G 6) (T 9))
> etc.
> 
> Why isn't base-counts being reinitialized each time?
> 
> Thanks for any help,
> 
> Sean

Jim is right. Take a look at 
http://www.lispworks.com/reference/HyperSpec/Body/s_quote.htm
It points out:
The consequences are undefined if literal objects (including quoted 
objects) are destructively modified.

So the value of your BASE-COUNTS variable is (in your implementation) 
permanently modified each time you call COUNT-BASES.

To be on the safe side you need to do something like:
(let ((base-counts (mapcar #'(lambda (elt) (list elt 0)) '(a c g t))) ...
Jim's solution is fine, but it's too much typing for me! :)

Even this won't work:
(let ((base-counts (copy-seq '((a 0) (c 0) (g 0) (t 0)))) ...
since you are modifying the sublists not the top-level list.

David Sletten
From: Simon Katz
Subject: Re: value not reinitialized on subsequent function calls
Date: 
Message-ID: <n6tpq0lc8tpqrlqh2n3un6mvqonqbpijmp@4ax.com>
On Tue, 30 Nov 2004 22:20:52 GMT, David Sletten <·····@slytobias.com>
wrote:

>Even this won't work:
>(let ((base-counts (copy-seq '((a 0) (c 0) (g 0) (t 0)))) ...
>since you are modifying the sublists not the top-level list.

COPY-TREE (instead of COPY-SEQ) will work.


___________________
Real email address:
(substitute ··@ #\+ (substitute #\s #\! "u!enet001+nomi!tech.com"))
From: Jim Newton
Subject: Re: value not reinitialized on subsequent function calls
Date: 
Message-ID: <31473eF36pl50U1@individual.net>
I think your problem is that the quote ' does
not do any memory allocation and you are destructively
mofitying the list including modifying the function itself.
You need to have some sort of list copy on base-counts
to protect the data from the destructive modification.

e.g.,
(let ((base-counts (list (list 'a 0) (list 'c 0) (list 'g 0) (list t 0)))

-jim

Sean Winship wrote:
>     (let ((base-counts '((a 0) (c 0) (g 0) (t 0)))
From: Kenneth Tilton
Subject: Re: value not reinitialized on subsequent function calls
Date: 
Message-ID: <ktilton-C1DECD.17212130112004@nycmny-nntp-rdr-03-ge1.rdc-nyc.rr.com>
In article <···············@individual.net>,
 Jim Newton <·····@rdrop.com> wrote:

> I think your problem is that the quote ' does
> not do any memory allocation and you are destructively
> mofitying the list including modifying the function itself.

Yes. This is like modifying a string literal in C, if the OP is familiar 
with that language.

> You need to have some sort of list copy on base-counts
> to protect the data from the destructive modification.
> 
> e.g.,
> (let ((base-counts (list (list 'a 0) (list 'c 0) (list 'g 0) (list t 0)))

or:

   (let ((base-counts (loop for base in '(a c g tee)
                            collecting (list base 0))))...

Not that 't is not a nice symbol. I don't know, maybe there would be no 
ill consequences. Well, if you forget to quote the other three there 
would likely be a compiler warning, but t would not.

btw, if loop seems too advanced:

      (mapcar (lambda (base) (list base 0)) 
          '(a c g tee))

kenny
From: Brian Downing
Subject: Re: value not reinitialized on subsequent function calls
Date: 
Message-ID: <la8rd.591751$mD.383024@attbi_s02>
In article <·····························@nycmny-nntp-rdr-03-ge1.rdc-nyc.rr.com>,
Kenneth Tilton  <·······@nyc.rr.com> wrote:
> btw, if loop seems too advanced:
> 
>       (mapcar (lambda (base) (list base 0)) 
>           '(a c g tee))

For perversity:

(mapcar #'list '(a c g tee) '#1=(0 . #1#))

Though honestly for the original poster

(copy-tree '((a 0) (c 0) (g 0) (t 0)))

is probably best.  Short and easy to understand.

-bcd
-- 
*** Brian Downing <bdowning at lavos dot net> 
From: Sean Winship
Subject: Re: value not reinitialized on subsequent function calls
Date: 
Message-ID: <7bd2848c.0412010630.6baee877@posting.google.com>
I'd like to thank everyone who replied.  I got an "Aha!" moment out of
the responses.

Thanks again,

Sean