在常见的lisp中,有没有办法接收用户输入,比如"foo"
和defvar
全局变量*foo*
?
例如(不起作用):
(defun global-name (s)
"Takes s and changes it to *s*"
(concatenate 'string "*" s "*"))
(defun add-global-var (var)
"defvars a global variable and adds it to *global-list*"
(let ((var-name (global-name var)))
(defvar var-name var)
(push var-name *global-list*)))
; Used like this:
(add-global-var "myvar")
在这种情况下,var-name
为string
,不适用于defvar
。
答案 0 :(得分:3)
Déjàvu...我在20多年前问过这些问题; - )
是的,你可以这样做(但没有,你做 不 想要!)
(defun add-global-var (var-name &optional (package *package*))
(let ((var (intern var-name package)))
(proclaim `(special ,var))
(push var *global-list*)))
请参阅
或者,您可以使用宏,如另一个答案建议的那样
事实上,宏观扩张时的符号创造(这是其中的一部分)
编译)是非常常见的东西,
比照gensym
虽然没有理由这样做。
在运行时创建的全局变量在编译时不可用 因此,它们毫无用处。
如果要将字符串映射到值,最好使用
equal
hash table。
如果您想与read
集成,
你应该在绑定时调用它
*package*
到你的内部临时包然后使用
symbol-value
存储和检索值。
您将使用intern
来
将“变量名称”映射到符号。
答案 1 :(得分:2)
是的,有一个宏:
(defvar *global-list* nil)
我更改了global-name
以便它也接受符号,以避免考虑字符串是否应该被提升。使用符号时,案例由readtable-case
给出(如果您想避免污染包裹,可以使用未加工的符号)。
(defun global-name (name)
(check-type name (or string symbol))
(intern
(concatenate 'string "*" (string name) "*")))
我将宏命名为defvar*
:
(defmacro defvar* (name)
`(push
(defvar ,(global-name name) ',name)
*global-list*))
试验:
CL-USER> (defvar* #:foo)
(*FOO*)
CL-USER> (defvar* #:bar)
(*BAR* *FOO*)
注意:
你也可以在@ sds的答案中添加一个可选的包参数,这样做会更好。
答案 2 :(得分:2)
这是logic analyzer snippet of BLE packets,因为在运行时需要创建一个名称变量是非常不寻常的。它在编译时很常见,但不是运行时。 @coredump已经涵盖了编译时宏,如果你正在使用它。
这是你如何做到的:
(defun add-global-var (var)
"defvars a global variable and adds it to *global-list*"
(let ((var-name (intern (string-upcase (global-name var)))))
(set var-name var)
(push var-name *global-list*)))
set
已被弃用,但我怀疑它是否会被删除。实现可能无法快速运行,因为这就像搞乱内部。
由于这些名称不是来自您,因此您没有很好地使用这些出价。因为这个我宁愿使用哈希:
(defvar *bindings* (make-hash-table :test #'eq))
(defun add-binding (var)
(let ((var-name (intern (string-upcase (global-name var)))))
(setf (gethash var-name *bindings*) var)
*bindings*))
这样做的一个原因是你自己的小翻译符号表或其他东西的一部分。您不需要它们的列表,因为您可以从哈希中获取所有键以及获取绑定值。