2

Practical Common Lisp で作業しようとしています。私はリスプ初心者です。

「quicklisp」を使用してパッケージを定義しました。パッケージをロードします (ql:quickload :spam filter)

このパッケージの関数の 1 つは次のようになります。

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

この関数を呼び出す関数をスライムで呼び出そうとすると、case ステートメントが失敗します。コンパイラがパッケージ名をプレフィックスとして句に追加したため、失敗したと思います。

これが私が見ているエラーです:

HAM は ECASE 式で落ちました。(HAM SPAM) の 1 つを求めていました。【タイプ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 "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:コーパス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

異なるパッケージのシンボルを比較しようとして解決する方法:

  • 通常、シンボルが正しいパッケージにあることを確認することは理にかなっています。それらを 1 つのパッケージに正規化します。

  • キーワード記号を使用する

  • シンボル名のみを比較しますが、それ以外のものを使用する必要がありますECASE

  • 文字列を使用しますが、それ以外のものを使用する必要がありますECASE

于 2014-11-20T22:22:45.123 に答える