gpt4 book ai didi

macros - 检测全局范围的宏

转载 作者:太空宇宙 更新时间:2023-11-03 18:50:09 24 4
gpt4 key购买 nike

据我所知,Common Lisp 没有全局词法作用域,所以如果你想创建一个全局变量,你必须使用 defvar 而不是 setq。我正在尝试创建一个自动执行此操作的宏,即我想写

(= x 1)

无论我身在何处,它都能“正常工作”。我想宏看起来像

(defmacro = (name value)
`(,(if (is-global) 'defvar 'setf) ,name ,value))

如何写is-global

最佳答案

引入绑定(bind)

From what I understand, Common Lisp has no global lexical scope,

这部分是正确的,但有一些“典型”的解决方法。没有规范的实现,但是 searching for deflexical可以引导您进行一些实现。

so if you want to create a global variable you have to use defvar instead of setq. (emphasis added)

这是不正确的。在大多数情况下,您实际上并没有创建 变量。您将绑定(bind)引入环境。最常见的方法是使用 let 或作为 函数 的参数。例如:

(defun foo (bar)
;; in here, there's a variable `bar`
)

(let ((a ...))
;; a is bound in here

这些是词法绑定(bind),除非在源代码中标识变量的符号被声明为特殊的,这在 Common Lisp 中意味着它是一个动态作用域的变量。您可以进行特殊声明,例如:

(defun foo (bar)
(declare (special bar))
;; in here, there's a variable `bar`
)

(let ((a ...))
(declare (special a))
;; a is bound in here

现在,您还可以使用defparameterdefvar 引入全局变量。这些全局将变量声明为特殊变量。

更新绑定(bind)

两种情况下,您都可以使用setqsetf 来更新变量的值。也就是说,您可以使用setqsetf 来更新词法变量和特殊变量的值。所以你可以这样做:

(defparameter *cat* (make-initial-cat))

(let ((cat (some-local-cat)))
(setf *cat* (make-instance 'cat)) ; update global/dynamic
(setf cat (make-instance 'cat)) ; update local/lexical

setf 在这两种情况下都适用,所以听起来您正在寻找的赋值运算符只是 setf

听起来您正在尝试解决的问题是您不应该将 setf/setq 与未声明的变量一起使用。事实上,这是未定义的行为。所以听起来你试图让你的赋值运算符在周围环境中没有变量的情况下自动引入一个变量。您不能这样做,至少有两个原因:

  1. 您如何知道是引入词法变量还是动态变量?不能从周围环境判断,因为如果周围环境已经有了,就不用再引入了。
  2. 无法检查它是否已声明为局部变量或动态变量。有一些变通方法在某些情况下会起作用,但环境访问不是标准 Common Lisp 的一部分。 (参见相关问题:Macro to detect global scope。一些实现确实实现了 CLtL2 environnments API。)

关于macros - 检测全局范围的宏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29460766/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com