【问题标题】:Use package shadowing symbols使用包阴影符号
【发布时间】:2017-06-16 18:52:00
【问题描述】:

例如,我有这个包定义,它会影响 COMMON-LISP:LISTEN :

(defpackage :shadows
  (:use :common-lisp)
  (:shadow #:listen)
  (:export #:listen))

然后我想从另一个包中使用这个包,比如说

(defpackage :light
  (:use :common-lisp
        :shadows))

如果我在使用包时实际上无法覆盖 Common Lisp 符号,那么阴影的目的是什么?

【问题讨论】:

  • 您可能想要做的是构建一个“类似”CL 但其中一些符号不同的包。您可能想查看conduits,它可以让您执行此操作。 (免责声明:我写了这篇文章,很惭愧地说我目前没有全世界可见的副本:这是别人的)。

标签: package lisp common-lisp


【解决方案1】:

简单

defpackage:shadow 参数 影响包shadows的定义, 不是后来在light 中使用shadows

你需要使用shadowing-import:

(defpackage #:shadows
  (:use #:common-lisp)
  (:shadow #:listen)
  (:export #:listen))
(defpackage #:light
  (:shadowing-import-from #:shadows #:listen)
  (:use #:common-lisp #:shadows))
(eq 'light::listen 'shadows:listen)
==> T
(describe 'light::listen)
==>
SHADOWS:LISTEN is the symbol SHADOWS:LISTEN, lies in #<PACKAGE SHADOWS>,
is accessible in 2 packages LIGHT, SHADOWS.

 #<PACKAGE SHADOWS> is the package named SHADOWS.
 It imports the external symbols of 1 package COMMON-LISP and
 exports 1 symbol to 1 package LIGHT.

散装

如果您需要进行批量阴影,则需要使用单独的函数 (make-package, import, export, shadow, use-package):

(defparameter *my-shadow-list* '(#:car #:cdr))
(make-package '#:my-package :use nil)
(import *my-shadow-list* '#:my-package)
(export *my-shadow-list* '#:my-package)
(shadow *my-shadow-list* '#:my-package)
(use-package '#:cl '#:my-package)
(make-package '#:my-user)
(shadowing-import *my-shadow-list* '#:my-user)
(use-package '(#:cl #:my-package) '#:my-user)
(describe 'my-user::car)
==>
MY-PACKAGE:CAR is the symbol MY-PACKAGE:CAR, lies in #<PACKAGE MY-PACKAGE>,
is accessible in 2 packages MY-PACKAGE, MY-USER.

 #<PACKAGE MY-PACKAGE> is the package named MY-PACKAGE.
 It imports the external symbols of 1 package COMMON-LISP and
 exports 2 symbols to 1 package MY-USER.

您可能会发现macroexpand-1 在决定如何到达您需要去的地方时很有用:

(macroexpand-1 '(defpackage #:light
                 (:shadowing-import-from #:shadows #:listen)
                 (:use #:common-lisp #:shadows)))
==>
(EVAL-WHEN (:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)
 (SYSTEM::%IN-PACKAGE "LIGHT" :NICKNAMES 'NIL :USE 'NIL :CASE-SENSITIVE NIL
  :CASE-INVERTED NIL)
 (SYSTEM::SHADOWING-IMPORT-CERROR "LISTEN" "SHADOWS" NIL "LIGHT")
 (USE-PACKAGE '("COMMON-LISP" "SHADOWS") "LIGHT") (FIND-PACKAGE "LIGHT")) ;
T

PS。隐藏 ANSI CL 标准名称对于您的代码可读性来说并不是一个好主意。

【讨论】:

  • 好吧,我有几十个这样的符号,所以每次我想使用这个很多阴影包时,我都必须明确:shadowing-import-from,这有点糟糕,真的。我知道这不是你的错,谢谢。
  • 如果DEFPACKAGE 只是按顺序堆叠使用的包符号而不引发冲突错误,那对我来说非常好。
  • 您可以使用shadowing-import 进行批量阴影或时光倒流50 年,并让Lisp 设计师相信您“按顺序堆叠使用过的包符号”的想法是个好主意。请注意,当所有符号都在所有包中时,您将不得不解释如何从 p1s2 进行 s1 的阴影导入;-)
  • 我不能只影响defpackage 吗? =D
  • @thodg UIOP:DEFINE-PACKAGE:MIX
【解决方案2】:

好的,实际上有一个方便的方法可以做到这一点。

在我的 many-shadows 包中,我导出了一个 shadowing-import-from 函数。它看起来像这样:

(defun shadowing-import-from ()
  `(:shadowing-import-from :many-shadows
     ,@(package-shadowing-symbols :many-shadows)))

然后,在轻量级 defpackage 中,我只是 READ-EVAL 它:

(defpackage :light
  (:use :common-lisp
        :many-shadows)
  #.(many-shadows:shadowing-import-from))

所以很明显,有些东西被遮住了,我想优先使用来自许多阴影的符号。而且它足够短,可以记录下来并实用。

感谢@sds 将我指向:shadowing-import-from

【讨论】:

    【解决方案3】:

    如果我在使用包时不能真正覆盖 Common Lisp 符号,那么阴影的目的是什么?

    具有阴影符号列表的包的目的是解决该包使用包引起的冲突。阴影对导出的任何内容都没有影响。

    当一个包使用其他包时,当两个或多个使用的包以相同名称导出符号时,可能会发生冲突。类似地,使用的包和本地包中的符号之间也可能出现冲突。这些冲突被视为错误。在逐个符号的基础上,阴影消除了这些冲突。包中存在的符号被添加到其阴影符号列表中。然后,任何冲突都会以有利于该符号的方式静默解决。

    当从具有该状态的包的外部看待它时,作为阴影符号不会赋予符号任何特殊权力。

    对于每个包,如果需要,我们必须单独安排“可见性堆栈”,包括它自己的阴影符号。

    【讨论】:

      猜你喜欢
      • 2019-10-05
      • 1970-01-01
      • 1970-01-01
      • 2014-02-08
      • 1970-01-01
      • 2015-02-04
      • 2018-10-02
      • 2018-07-20
      • 2013-06-30
      相关资源
      最近更新 更多