let сохраняет значения между вызовами функции
Решаю задания из «Gentle introduction to symbolic computation», там на 369 странице просят написать в итеративном стиле подсчет нуклеотидов в строке. Проще говоря, количество символов найти.
Набросал такой код:
(defun count-bases (strand)
(let ((counts '((a . 0) (t . 0) (c . 0) (g . 0))))
(dolist (e strand counts)
(cond ((atom e) (incf (cdr (assoc e counts))))
(t (incf (cdr (assoc (car e) counts)))
(incf (cdr (assoc (cadr e) counts))))))))
Получилось в принципе похоже на код из ответов в конце книжки, только покороче:
(defun count-bases (dna)
(let ((acnt 0) (tcnt 0) (gcnt 0) (ccnt 0))
(labels ((count-one-base (base)
(cond ((equal base ’a) (incf acnt))
((equal base ’t) (incf tcnt))
((equal base ’g) (incf gcnt))
((equal base ’c) (incf ccnt)))))
(dolist (element dna)
(cond ((atom element) (count-one-base element))
(t (count-one-base (first element))
(count-one-base (second element)))))
(list (list ’a acnt)
(list ’t tcnt)
(list ’g gcnt)
(list ’c ccnt)))))
Мой вариант работает как-то странно:
* (COUNT-BASES NIL)
((A . 0) (T . 0) (C . 0) (G . 0))
* (COUNT-BASES '(A G T A C T C T))
((A . 2) (T . 3) (C . 2) (G . 1))
* (COUNT-BASES '((A T) (T A) (C G) (G C)))
((A . 4) (T . 5) (C . 4) (G . 3))
* (COUNT-BASES (MAKE-DOUBLE '(A T G C)))
((A . 6) (T . 7) (C . 6) (G . 5))
Значения в cdr-частях переменной counts аккумулируются, хотя я ожидаю что они должны быть новые при каждом вызове let. Почему так происходит? Это особенность реализации (компиляю в sbcl)?