对于由多个包组成的Common Lisp库,是否有一种导出API的标准方法?

时间:2012-10-18 07:56:26

标签: common-lisp

显然,外部可见的API是通过导出符号发布的。但是......如果我有多个包(例如A,B和C)并且A的导出符号并不都是外部API的一部分 - B和C需要它们中的一部分怎么办? (类似地,B为A和C导出一些符号,为外部API导出一些符号; C是'toplevel'包,它的所有导出符号都是公共API的一部分;我想保持模块化并允许A隐藏其内部来自B和C,所以我避免使用'::')。

我现在的解决方案是重新导出C中要公开的所有内容,并记录公共API仅包含C的导出符号,并且人们应该在错误和痛苦的情况下远离A和B的公共符号当内部接口发生变化时,代码将在未来被破坏。

有更好的方法吗?

更新:这是我对Xach答案理解的实现:

首先,让我完成我的例子。我想从包symbol-a-1导出符号symbol-a-2a,从包symbol-b-1导出符号symbol-b-2b以及符号api-symbol-1来自包api-symbol-2的{​​{1}}。只有从c导出的符号才是公共API的一部分。

首先,c的定义:

a

请注意,没有任何导出的符号: - )

辅助宏(使用亚历山大):

(defpackage #:a
  (:use #:cl))

使用宏来“私下导出”:-):

(defmacro privately-export (package-name &body symbols)
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     (defun ,(alexandria:format-symbol *package*
                                       "IMPORT-FROM-~a"
                                       (symbol-name package-name)) ()
       (list :import-from
             ,package-name
             ,@(mapcar (lambda (to-intern)
                         `',(intern (symbol-name to-intern) package-name))
                       symbols)))))

现在定义(privately-export :a :symbol-a-1 :symbol-a-2)

b

... (defpackage #:b (:use #:cl) #.(import-from-a)) 的'出口':

b

... (privately-export :b :symbol-b-1 :symbol-b-2) 的定义:

c

这种方法存在问题:

  • (defpackage #:c (:use #:cl) #.(import-from-a) #.(import-from-b) (:export :api-symbol-1 :api-symbol-2) 无法使用a中的符号(在b import之后b中没有a个符号;
  • 语法package:symbol基本上不适用于“私下”导出的符号(它只是symbolpackage::symbol)。

3 个答案:

答案 0 :(得分:2)

如果A和B主要用于实现C,那么你可以选择性地使用:import-from来使用C的defpackage表单驱动器,因为你可以导入非外部的东西。然后你可以从那里有选择地重新导出。

答案 1 :(得分:1)

您可以添加第三个包D,它导出所有公共API符号,并将A,B和C包视为私有。然后,您可以使用限定名称(例如

)限定API包中函数和变量的所有定义

(defun D:blah () ...)

可以直观地查看公共入口点的定义。

答案 2 :(得分:1)

可能最简单的方法是由Hans提出。

您可能还想看看Tim Bradshaw的Conduit packages