如何在Lisp中以字符串命名变量



我想在Lisp中重命名一个变量,并使用预先存在的字符串进行重命名。即,如果我的字符串是";abc";我希望Lisp将字符串作为我的变量的名称。有什么想法吗?

谢谢!

基于您的评论:

以下是我要做的:1。我正在为一种新语言编写一个解析器。2.语言的一部分涉及创建变量并命名它们。3.因此,用户输入:name:contents——其中name是变量的名称,contents是变量包含的内容。4.我想知道如何接受用户提供的name输入,并告诉Lisp创建一个变量并将其称为name

您几乎肯定不想将Lisp变量用于任何嵌入式语言。相反,在这种情况下,通常要做的是定义某种"环境"对象,该对象在您正在实现的语言中携带变量名称和值之间的映射。通常你想要对它进行以下操作。

  • 变量是否绑定在环境中
  • 从环境中检索绑定变量的值
  • 修改环境中绑定变量的值
  • 使用一个或多个新绑定扩展环境,返回一个新环境
  • 也许可以在不构建新环境的情况下为环境添加绑定

如果你可以不使用最后一个,那么这通常是好的,因为它将使你的语言的语义更容易理解,程序中的错误更容易捕捉,因为你不能分配给未绑定的变量。

环境结构实现的一个经典(但在某些情况下很慢(示例是关联列表。这很容易支持前三个,但实际上并不容易支持最后三个。

以下是一个假设变量由字符串命名的示例(因此您不需要为它们插入符号(:

(defconstant empty-environment '())
(defun variable-bound-in-environment-p (env var)
(if (assoc var env :test #'string=) t nil))
(defun variable-value-in-environment (env var)
(let ((binding (assoc var env :test #'string=)))
(unless binding
(error "unbound"))
(cdr binding)))
(defun (setf variable-value-in-environment) (new env var)
(let ((binding (assoc var env :test #'string=)))
(unless binding
(error "unbound"))
(setf (cdr binding) new)))
(defun extend-environment (env &rest vars/vals)
(labels ((ee-loop (e vvp)
(if (null vvp)
e
(destructuring-bind (var val . more) vvp
(ee-loop (acons var val e) more)))))
(ee-loop env vars/vals)))

现在:

> (variable-bound-in-environment-p empty-environment "foo")
nil
> (variable-value-in-environment
(extend-environment empty-environment "foo" 1)
"foo")
1
> (variable-value-in-environment
(extend-environment
(extend-environment empty-environment "foo" 1)
"foo" 2)
"foo")
2
> (variable-value-in-environment
(let ((e (extend-environment empty-environment "foo" 1)))
(setf (variable-value-in-environment e "foo") 2)
e)
"foo")
2

您可能希望使用Lisp符号作为变量名,这将使环境中的变量查找等更快、更好。出于这些目的,符号只是带有标识的字符串。要做到这一点,您需要将获得的字符串作为变量名,并对其进行"实习"以创建符号。一个很好的方法是将这些符号保留在它们自己的命名空间中,Common Lisp称之为"包",而不是破坏底层Lisp程序使用的命名空间:

(defvar *language-package* (make-package "LANGUAGE-PACKAGE" :use '()))
(defun intern-language-variable-name (s &optional (package *language-package*))
(intern s package))

现在你可以确定

> (eq (intern-language-variable-name "foo")
(intern-language-variable-name "foo"))
t

然后,在从解析器中获得字符串版本的变量名后,可以使用intern-language-variable-name对其进行实习生,然后在环境中使用这些对象,这样可以更快、更简单:

(defconstant empty-environment '())
(defun variable-bound-in-environment-p (env var)
(if (assoc var env) t nil))
(defun variable-value-in-environment (env var)
(let ((binding (assoc var env)))
(unless binding
(error "unbound"))
(cdr binding)))
(defun (setf variable-value-in-environment) (new env var)
(let ((binding (assoc var env)))
(unless binding
(error "unbound"))
(setf (cdr binding) new)))
(defun extend-environment (env &rest vars/vals)
(labels ((ee-loop (e vvp)
(if (null vvp)
e
(destructuring-bind (var val . more) vvp
(ee-loop (acons var val e) more)))))
(ee-loop env vars/vals)))

最新更新