First, proper indentation helps a lot. I do appreciate you not putting the closing parens on separate lines though. Thank you.
(defun string-to-list (string) (loop for char across string collect char)) (defun is-vowel (char) (find char "aeiou" :test #'char-equal)) (defun is-consonant (char) (find char "bcdfghjklmnpqrstvwxyz" :test #'char-equal)) (defun letter-type (char) (if (is-vowel char) "V" (if (is-consonant char) "C" "0"))) (defun analyze-word (word-string) (loop for char across word-string collect (letter-type char)))
We're talking about Common Lisp, so there's no call to go defining your own string-to-list
, especially if you're doing it in terms of loop
. You can do the same thing with a coerce
call.
CL-USER> (coerce "an example" 'list) (#\a #\n #\ #\e #\x #\a #\m #\p #\l #\e)
Though now that I look at it, you don't call string-to-list
anywhere anyway, so we may as well just remove the definition.
(defun is-vowel (char) (find char "aeiou" :test #'char-equal)) (defun is-consonant (char) (find char "bcdfghjklmnpqrstvwxyz" :test #'char-equal)) (defun letter-type (char) (if (is-vowel char) "V" (if (is-consonant char) "C" "0"))) (defun analyze-word (word-string) (loop for char across word-string collect (letter-type char)))
Common Lisp convention is to use a suffix of p
or -p
for predicates, rather than an is
prefix.
(defun vowel-p (char) (find char "aeiou" :test #'char-equal)) (defun consonant-p (char) (find char "bcdfghjklmnpqrstvwxyz" :test #'char-equal)) (defun letter-type (char) (if (vowel-p char) "V" (if (consonant-p char) "C" "0")))
You can use cond
rather than chaining if
s. Typically, this makes the intent clearer.
(defun letter-type (char) (cond ((vowel-p char) "V") ((consonant-p char) "C") (t "O")))
If you want to make the result of analyze-word
a string, you'll need to return a character rather than a string from letter-type
(defun letter-type (char) (cond ((vowel-p char) #\V) ((consonant-p char) #\C) (t #\O)))
At that point, you can coerce
its result.
CL-USER> (coerce (analyze-word "supercalifragilistiwhateverthefuck") 'string) "CVCVCCVCVCCVCVCVCCVCCVCVCVCCCVCVCC"
Since your function is taking a sequence of characters, and returning a sequence of characters in the same form, it's actually easier to define analyze-word
in terms of map
than in terms of loop
(in my experience, this is atypical but still worth looking out for).
(defun analyze-word (word-string) (map 'string #'letter-type word-string))
That will take "the function named letter-type
", apply it to each element of word-string
and return the resulting string
. This also saves you from having to coerce its result after the fact.
CL-USER> (analyze-word "supercalifragilistiwhateverthefuck") "CVCVCCVCVCCVCVCVCCVCCVCVCVCCCVCVCC"
Take this last point with a grain of salt though, because if you ever need to re-write analyze-word
to return something like (list :consonants 21 :vowels 13)
, you'll be right back to loop
.