Common lisp Common Lisp:定义打包和导出程序创建的符号

Common lisp Common Lisp:定义打包和导出程序创建的符号,common-lisp,packages,Common Lisp,Packages,在调用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)) (defparam

在调用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|)
我在“常见Lisp包的完整白痴指南”中读到 “现在,您已经了解了可以使用的无数函数和宏 用来操纵软件包你不应该真的使用它们中的任何一个, 导入、导出、阴影等的所有功能都集中在一个 一个名为DEFPACKAGE的宏,这是您应该用于real(非real)的宏- 原型)代码。“


我上面的代码中有代码气味吗?另外,您将如何导出其他符号(猫狗动物类型,等等,它们有很多)以避免重复?

如果不了解更多您的意图和要求,很难说很多,但在许多情况下,最好有一个或多个包含动态生成对象的哈希表(或类似表),然后导出哈希表的符号

这里有一个手波浪的例子,说明了这是如何工作的。如果您可以编辑和添加更多关于您的需求和约束的信息,我会看看是否可以提供更多帮助

(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
我使用关键字作为名称而不是符号,因为关键字不是包的本地关键字(或者,更具体地说,它们都是
关键字
包的本地代码。如果您改为使用
'foo
'bar
,您将重新需要导出这些符号,或者您的用户在引用它们时需要使用包标识符(例如
(get'package-a::foo)

您也可以使用字符串作为键,不过在这种情况下,您可能希望创建具有
(使哈希表:test'equal)
的表。默认哈希表测试是
#eql
,它不会适当地比较字符串。将关键字与
#eql
进行比较要比将字符串与
#equal
进行比较快(因为关键字是一个简单的指针比较,而不是字符串所需的逐字符比较),但除非您有明确的理由不这么认为,否则差异可能是微不足道的


这种方法为您的用户提供了更好的界面,因为现在您已经定义了入口点、docstring的机会、默认值,并且在REPL上可以更轻松地进行探索。

如果不了解您的意图和需求,很难说太多,但在许多情况下,最好有一个或多个哈希表(或类似)包含动态生成的对象,然后为哈希表导出符号

这里有一个手波浪的例子来说明这是如何工作的。如果你能编辑并添加更多关于你的需求和约束的信息,我会看看我是否能提供更多帮助

(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
我使用关键字作为名称而不是符号,因为关键字不是包的本地关键字(或者,更具体地说,它们都是
关键字
包的本地代码。如果您改为使用
'foo
'bar
,您将重新需要导出这些符号,或者您的用户在引用它们时需要使用包标识符(例如
(get'package-a::foo)

您也可以使用字符串作为键,不过在这种情况下,您可能希望创建具有
(使哈希表:test'equal)
的表。默认哈希表测试是
#eql
,它不会适当地比较字符串。将关键字与
#eql
进行比较要比将字符串与
#equal
进行比较快(因为关键字是一个简单的指针比较,而不是字符串所需的逐字符比较),但除非您有明确的理由不这么认为,否则差异可能是微不足道的


这种方法为您的用户提供了更好的界面,因为现在您已经定义了入口点、docstring的机会、默认值以及在REPL上更容易的探索。

什么是“气味”首先,您需要导出这么多动态创建的符号。更高级别的意图是什么?我相信这可以通过其他五十种方式完成,但我对Common Lisp不熟悉,我最终得到了一个组织,其中这些符号的定义与我使用它们的包不同,我需要导出它们。也许吧ps我没有正确表达我的问题,我的符号不是动态生成的,生成它们的函数只填充其他符号名称一次(在defparameter其他符号名称内)在那之后它们不会改变。只是它们是许多符号,大约100个。你在示例中给出的名称看起来像是使用了很多编号符号,可能只是几个数组。“气味”是什么首先,您需要导出这么多动态创建的符号。更高级别的意图是什么?我相信这可以通过其他五十种方式完成,但我对Common Lisp不熟悉,我最终得到了一个组织,其中这些符号的定义与我使用它们的包不同,我需要导出它们。也许吧ps我没有正确表达我的问题,我的符号不是动态生成的,生成它们的函数只填充其他符号名称一次(在defparameter其他符号名称内)之后它们不会改变。只是它们是许多符号,大约100个。您在示例中给出的名称看起来可能使用了许多编号符号,这些符号可能只是几个数组。谢谢您的回答,尽管我想这比我需要的要复杂。您不应该使用
get
,因为这是从
common lisp
包导出的符号(访问器
get
在符号属性列表中进行查找)。@Svante,您说得对,因为进入细节将不必要地复杂化