如何判断调用环境?

CL-*_*SER 3 common-lisp

我正在尝试隐藏 CL 包中的数学运算符。除了*/和 之外+,这工作正常。然而,这些符号的符号值由实现设置为我在 REPL 中经常使用的值(该函数位于interactive-evalSBCL 中)。

cl:*由于它们是在之前的表单评估中设置的,因此除了通过 CL 包中的符号(即在评估表单之后)之外,我无法获取它们。我考虑制作*一个符号宏,如果在函数上下文中,则可以在我的向量化版本上调度*,或者返回否则的值cl:*

然而,似乎没有一种简单的方法来确定符号是否被用作函数或值。

到目前为止我得到的一个程式化版本是:

(in-package :my-math-package)
(setf (fdefinition '+)   #'my-vectorised-version-of-+)`
Run Code Online (Sandbox Code Playgroud)

由于我的函数版本+是 CL 的超集,因此一切正常,除了*在我的包中尝试在 REPL 中使用之外。我可以使用cl:*并且它可以工作,但我试图保持cl:*my-package:*值槽同步。

符号值的一种类比可能是: (setf (symbol-value '+) #'cl:+)

但这不起作用有两个原因:

  1. 编译时cl:*没有符号值
  2. cl:*即使这样做,它也不会具有上次评估表单的当前值,它将具有当时值的“快照” 。

所以我需要动态地保持my-package:*cl:*具有相同的符号值。

有人有主意吗?我错过了一些明显的东西吗?

ign*_*ens 5

这是 CL 封装系统的经典边缘情况。然而,对于大多数用途,符号宏可以满足您的需求。

举个例子,如果我在一个*不在其中的包中cl:*,那么我可以这样说:

(defun * (a b)
  (+ a b))

(define-symbol-macro * cl:*)
Run Code Online (Sandbox Code Playgroud)

现在

> (* 1 2)
3

> *
3

> (funcall #'* 3 4)
7

> *
7
Run Code Online (Sandbox Code Playgroud)

这是因为符号宏影响对值的符号的引用,而不是对其函数定义的引用。

您将失去的是绑定并使该绑定变得特殊的能力*,因为您无法将符号宏声明为特殊的。所以

> (funcall (let ((* 2))
             (lambda () *)))
2
Run Code Online (Sandbox Code Playgroud)

例如。对于 来说这可能不是一个大问题*

更重要的是,您还将失去*任何仅用作符号的地方。例如(declare (type (array * (* *))) ...),根本不再起作用。您对此无能为力,因为这些只是*作为符号使用。这是软件包系统的固有限制。


顺便说一句:如果您重载数字字段的运算符(so*+),您可能会比人们通常更努力地考虑一致性。或者干脆放弃一致性,这就是人们通常所做的。特别(+)是应该返回该字段的 0,并且(*)应该返回该字段的 1。但是……哪个领域?