2

defpackage マクロを呼び出した時点でシンボルをまだ作成していない場合、パッケージからシンボルをどのようにエクスポートしますか?

(defpackage :package-a
  (:use :cl)
  (:export :fruit-type :animal-type :orange :apple :peach :cat :dog))

(deftype fruit-type () '(member ORANGE APPLE PEACH))
(deftype animal-type () '(member CAT DOG))

(defparameter *other-symbol-names*
  '("A1" "A2" "B1" "B2")) ;imagine a longer list here
                          ;with names generated by a function

(defparameter *other-symbols*
  (mapcar #'(lambda (sym-name)
          (import (make-symbol sym-name))
          (find-symbol sym-name))
      *other-symbol-names*))

(mapcar #'export *other-symbols*)

(setf A1 32 A2 33 B1 34 B2 35)

また、別のパッケージがあります

(defpackage :package-b
  (:use :cl :package-a))
(in-package :package-b)
(format nil "~a ~a ~a ~a" |A1| |A2| |B1| |B2|)

私は「The Complete Idiot's Guide to Common Lisp Packages」を読んだことがあります。 IMPORT、EXPORT、SHADOW などの機能のすべては、DEFPACKAGE と呼ばれる単一のマクロにまとめられています。これは、実際の (非プロトタイプ) コードに使用する必要があります。"

上記のコードにコードの匂いはありますか? また、重複を避けるために、他のシンボル (猫、犬、動物の種類など - それらの多くがあります) をどのようにエクスポートしますか?

4

1 に答える 1

3

意図と要件について詳しく知ることなく多くを語ることは困難ですが、多くの場合、動的に生成されたオブジェクトを含む 1 つ以上のハッシュ テーブル (または類似のもの) を用意し、ハッシュのシンボルをエクスポートする方がよいでしょう。テーブル。

以下は、これがどのように機能するかを示す手の波のような例です。要件と制約に関する情報を編集して追加できる場合は、さらに支援できるかどうかを確認します.

(in-package :cl)

(defpackage :package-a
  (:use :cl)
  (:export *objects* put get)
  (:shadow get))

(in-package :package-a)

(defvar *objects* (make-hash-table)
  "Container for dynamically generated objects we want to expose to the
  package's user.")

(defun put (name obj)
  (setf (gethash name *objects*) obj))

(defun get (name &optional default)
  (gethash name *objects* default))

;; Your code can put arbitrary objects into the hash table
(put :foo (lambda () :a-thunk))
(put :bar (lambda () :another))

;; And your users can retrieve them
(in-package :cl-user)
(use-package :package-a)
(funcall (get :foo)) ;; => :a-thunk

キーワードはパッケージに対してローカルではないため (または、より具体的には、それらはすべてパッケージに対してローカルであるため)、シンボルではなく名前にキーワードを使用しました。keyword代わりに使用し、それらのシンボルをエクスポートする必要が戻ってくる場合、またはユーザーがそれらを参照するときにパッケージ指定子を使用する必要があります (例: )。'foo'bar(get 'package-a::foo)

文字列をキーとして使用することもできますが、その場合は(make-hash-table :test 'equal). デフォルトのハッシュ テーブル テストは#'eqlで、文字列を適切に比較しません。キーワードと#'eqlの比較は、文字列との比較よりも高速ですが#'equal(文字列に必要な文字ごとの比較とは対照的に、キーワードは単純なポインター比較であるため)、別の方法で考える特別な理由がない限り、その違いはおそらく重要ではありません。

このアプローチは、エントリ ポイント、docstrings、デフォルトの機会、REPL での探索の容易さを定義したので、ユーザーにより良いインターフェイスを提供します。

于 2013-09-21T01:47:58.663 に答える