试图更好地使用 Lisp,我遇到了以下问题:
(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))
在我看来,这通过增加 plist 来计算每个元音。但是,当我使用例如
调用该函数时(countVowels "test")
输出是
A, 0, E, 0, I, 0, O, 0, U, 0
代码不正确。您正在符号列表中搜索字符。为了让它最低限度地工作,您需要将
vowels
初始化为
(setf vowels (list #\a 0 #\e 0 #\i 0 #\o 0 #\u 0))
但是,它仍然存在一些问题。
setf
用于分配给现有变量,而不是创建新变量。虽然它将回退到创建变量,但 SBCL 对此发出了警告。我们应该使用 let
来代替,或者只是在 with
宏中使用 loop
块。
此外,命名约定只是在骗你。 Common Lisp 不区分大小写,因此
countVowels
和 COUNTVOWELS
,甚至 CoUnTvOwElS
之间没有区别。我们通常倾向于在 Common Lisp 中坚持一种情况,只是为了保持一致。
最后,没有令人信服的理由在函数内部进行打印。这只会夺走调用者的权力。相反,返回 plist,并让调用者决定如何处理它。如果你不想严重依赖
loop
宏,你可以写
(defun count-vowels (string)
(let ((vowels (list #\a 0 #\e 0 #\i 0 #\o 0 #\u 0)))
(loop for ch across string
when (getf vowels ch)
do (incf (getf vowels ch)))
vowels))
(format t "~{~a~^, ~}" (count-vowels "test"))
或者你可以全力以赴
loop
并写作
(defun count-vowels (string)
(loop with vowels = (list #\a 0 #\e 0 #\i 0 #\o 0 #\u 0)
for ch across string
when (getf vowels ch)
do (incf (getf vowels ch))
finally (return vowels)))
(format t "~{~a~^, ~}" (count-vowels "test"))