Trying to get better in Lisp, I came across the following problem:
(defun countVowels (string)
(setf vowels (list 'a 0 'e 0 'i 0 'o 0 'u 0))
(loop for ch across string
when (member ch vowels)
do (incf (getf vowels ch)))
(format t "~{~a~^, ~}" vowels))
In my opinion, this counts every vowel by incrementing the plist. However, when I invoke the function with e.g.
(countVowels "test")
the output is
A, 0, E, 0, I, 0, O, 0, U, 0
The code is incorrect. You're searching for characters in a list of symbols. To get it minimally working, you'll need to initialize
vowelsasHowever, it still has some issues.
setfis used to assign to existing variables, not create new ones. While it will fall back to creating variables, SBCL issues a warning for this. We should be usingletinstead, or simply awithblock inside theloopmacro.Additionally, the naming convention is just flat lying to you. Common Lisp is case-insensitive, so there's no difference between
countVowelsandCOUNTVOWELS, or evenCoUnTvOwElS. We usually tend to stick to one case in Common Lisp, just to keep things consistent.Finally, there's no compelling reason to print inside the function. That just takes power away from the caller. Return the plist instead and let the caller decide what to do with it. If you don't want to rely heavily on the
loopmacro, you can writeor you can go all-in on
loopand write