I am trying to work through Practical Common Lisp. I'm a lisp beginner.
I've defined a package using "quicklisp" I load the package with (ql:quickload :spam filter)
One of the functions in this package looks like this:
(defun increment-count (feature type)
(ecase type
(ham (incf (ham-count feature)))
(spam (incf (spam-count feature)))))
When I try to call a function that calls this function in slime the case statement fails. I think it fails because the compiler has added the package name as a prefix to the clauses.
Here is the error I'm seeing:
HAM fell through ECASE expression. Wanted one of (HAM SPAM). [Condition of type SB-KERNEL:CASE-FAILURE]
Restarts: 0: [RETRY] Retry SLIME REPL evaluation request. 1: [*ABORT] Return to SLIME's top level. 2: [ABORT] Abort thread (#)
Backtrace: 0: (SB-KERNEL:CASE-FAILURE ECASE HAM (SPAMFILTER::HAM SPAMFILTER::SPAM)) 1: (SPAMFILTER:INCREMENT-COUNT # HAM) 2: (SPAMFILTER:TRAIN "From exmh-users-admin@redhat.com Mon Sep 23 12:06:27 2002 ..) 3: (SPAMFILTER::TRAIN-FROM-CORPUS #>((#P"/Users/jh/src/lisp/spamfilter/mail/easy_ham/1205.f9d66868c52039f7a147d9e2b4b05e1f" HAM) (#P"/Users/jh/src/lisp/spamfilter/mail/easy_ham/0090.314ec4268af7a3a1974d5e.. 4: (SPAMFILTER:TEST-CLASSIFIER #((#P"/Users/jh/src/lisp/spamfilter/mail/easy_ham/0001.ea7e79d3153e7469e7a9c3e0af6a357e" HAM) (#P"/Users/jh/src/lisp/spamfilter/mail/easy_ham/0002.b3120c4bcbf3101e661161ee7.. 5: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SPAMFILTER:TEST-CLASSIFIER SPAMFILTER:CORPUS 0.1) #) 6: (EVAL (SPAMFILTER:TEST-CLASSIFIER SPAMFILTER:CORPUS 0.1)) --more--
I'm basing my conjecture that the compiler has added the prefix on Backtrace 0:
0: (SB-KERNEL:CASE-FAILURE ECASE HAM (SPAMFILTER::HAM SPAMFILTER::SPAM))
I'm sure I'm missing something obvious.
Thanks.
This REPL transcript may be instructive. This doesn't have anything to do with the compiler adding anything, but that symbols in different packages aren't necessarily the same.
First, define a package and some a function using symbols in the spam-filter package:
CL-USER> (defpackage #:spam-filter
(:use "COMMON-LISP"))
#<PACKAGE "SPAM-FILTER">
CL-USER> (in-package #:spam-filter)
#<PACKAGE "SPAM-FILTER">
SPAM-FILTER> (defun test (x)
(ecase x
(ham "ham")
(spam "spam")))
TEST
Let's check that it works:
SPAM-FILTER> (test 'spam)
"spam"
OK, now let's go back to CL-USER:
SPAM-FILTER> (in-package "CL-USER")
#<PACKAGE "COMMON-LISP-USER">
Now let's try to call spam-filter::test:
CL-USER> (spam-filter::test 'spam)
; Evaluation aborted on #<SB-KERNEL:CASE-FAILURE expected-type:
(MEMBER SPAM-FILTER::HAM SPAM-FILTER::SPAM)
datum: SPAM>.
We get an error because the current package is CL-USER, so the reader reads the characters spam
and interns "SPAM" to get the symbol cl-user::spam, which is not the same as spam-filter::spam. Let's try calling it with spam-filter::spam:
CL-USER> (spam-filter::test 'spam-filter::spam)
"spam"
And surely enough, it still works. For more about what's going on here, you might enjoy Ron Garret's The Complete Idiot’s Guide to Common Lisp Packages.