如何将用户输入全局定义为变量

时间:2018-01-03 21:42:29

标签: common-lisp

在常见的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-namestring,不适用于defvar

3 个答案:

答案 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

您的问题

虽然没有理由这样做。

在运行时创建的全局变量在编译时不可用 因此,它们毫无用处。

Why do you want to do this?

如果要将字符串映射到值,最好使用 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*))

这样做的一个原因是你自己的小翻译符号表或其他东西的一部分。您不需要它们的列表,因为您可以从哈希中获取所有键以及获取绑定值。