2

我正在尝试通过 Practical Common Lisp 工作。我是一个口齿不清的初学者。

我已经使用“quicklisp”定义了一个包我用(ql:quickload:spam filter)加载了这个包

这个包中的一个函数如下所示:

    (defun increment-count (feature type)
     (ecase type
      (ham (incf (ham-count feature)))
      (spam (incf (spam-count feature)))))

当我尝试调用在 slime 中调用此函数的函数时,case 语句失败。我认为它失败了,因为编译器已将包名称添加为子句的前缀。

这是我看到的错误:

HAM 通过 ECASE 表达下降。想要一个(HAM SPAM)。[SB-KERNEL:CASE-FAILURE 类型的条件]

重新启动:0:[RETRY] 重试 SLIME REPL 评估请求。1: [*ABORT] 返回 SLIME 的顶层。2: [ABORT] 中止线程 (#)

回溯: 0: (SB-KERNEL:CASE-FAILURE ECASE HAM (SPAMFILTER::HAM SPAMFILTER::SPAM)) 1: (SPAMFILTER:INCREMENT-COUNT # HAM) 2: (SPAMFILTER:TRAIN "来自 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-LEXV (SPAMFILTER:TEST-CLASSIFIER SPAMFILTER: CORPUS 0.1) #) 6: (EVAL (SPAMFILTER:TEST-CLASSIFIER SPAMFILTER:语料库0.1)) --更多--

我的猜测是编译器在 Backtrace 0 上添加了前缀:

0: (SB-KERNEL:CASE-FAILURE ECASE HAM (SPAMFILTER::HAM SPAMFILTER::SPAM))

我确定我遗漏了一些明显的东西。

谢谢。

4

2 回答 2

4

此 REPL 成绩单可能具有指导意义。这与编译器添加任何东西没有任何关系,但是不同包中的符号不​​一定相同。

首先,使用spam-filter包中的符号定义一个包和一些函数:

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

让我们检查它是否有效:

SPAM-FILTER> (test 'spam)
"spam"

好的,现在让我们回到 CL-USER:

SPAM-FILTER> (in-package "CL-USER")
#<PACKAGE "COMMON-LISP-USER">

现在让我们尝试调用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>.

我们得到一个错误,因为当前包是 CL-USER,所以阅读器读取字符spam和实习生 "SPAM" 以获取符号cl-user::spam,这spam -filter::spam不同。让我们尝试使用spam-filter::spam调用它:

CL-USER> (spam-filter::test 'spam-filter::spam)
"spam"

当然,它仍然有效。有关此处发生的更多信息,您可能会喜欢 Ron Garret 的The Complete Idiot's Guide to Common Lisp Packages

于 2014-11-20T22:16:26.707 回答
1

尝试比较来自不同包的符号的解决方法:

  • 通常确保符号在正确的包中是有意义的。将它们规范化为一个包。

  • 使用关键字符号

  • 仅比较符号名称,但随后您需要使用 . 以外的其他内容ECASE

  • 使用字符串,但是你需要使用除ECASE.

于 2014-11-20T22:22:45.123 回答