LISP参数绑定

时间:2017-07-20 15:49:13

标签: parameters binding lisp common-lisp

我必须定义一个 LISP 函数,该函数为参数分配另一个函数的结果,如下所示:

(defun assign-param (x)
  (defparameter param (generic-funct x)))

在第一次调用时,assign-param的结果为PARAM。如果我再做一次调用,函数assign-param将再次返回PARAM,但这样:

Warning: (DEFVAR PARAM) defined more than once in 
C:\Users\****\Desktop\****\****.lisp.
PARAM

我尝试使用defvar代替defparameter,结果相同。

有没有办法避免这条警告信息?

如果已存在其他参数,有没有办法自动生成? (例如:如果param已经在内存中,则分配给param1,param2 ......)

2 个答案:

答案 0 :(得分:6)

你做的事情非常糟糕。

defvar and defparameter"top-level" forms

没有理由在函数中使用它们。

您可能想要做的事情就像

(defvar *param*)
(defun assign-param (x)
  (setq *param* (generic-funct x))
  '*param*) ; so that `assign-param` returns the symbol instead of the new value, like `defvar`

但是,关于param1param2& c的最后一个问题很少 感觉(是的,它可以做到,而且,不,你做想要这样做。)

您可能想做什么

您似乎想拥有一组全局参数,例如,环境或配置文件动态设置。

有两种主要方法:哈希表和包。

Hash Tables

简单直接;将任何值与任何字符串相关联:

(defvar *parameters* (make-hash-table :test 'equal))
(defun param-value (param-name)
  (gethash param-name *parameters*))
(defun (setf param-value) (new-value param-name)
  (setf (gethash param-name *parameters*) new-value))
(param-value "foo")
==> NIL; NIL
(setf (param-value "foo") "bar")
==> "bar"
(param-value "foo")
==> "bar"; T
(defun delete-param (param-name)
  (remhash param-name *parameters*))

请注意,如果gethash的第二个值为param-value,则应修改nil以表示错误,即参数不存在。

Packages

更多参与,但您可以将更多“东西”与参数对象相关联:

(defvar *parameters* (make-package "parameters" :use ()))
(defun param-value (param-name)
  (multiple-value-bind (param status) (find-symbol param-name *parameters*)
    (unless status
      (error "Parameter %s does not exist" param-name))
    (symbol-value param)))
(defun (setf param-value) (new-value param-name)
  (setf (symbol-value (intern param-name *parameters*)) new-value))
(defun delete-param (param-name)
  (multiple-value-bind (param status) (find-symbol param-name *parameters*)
    (when status
      (unintern param))))

这种方法的主要优点是read与包的集成,这将使配置文件解析更容易。

一个小优点是,您不仅可以在参数中存储value,还可以存储functionproperty list

答案 1 :(得分:2)

尝试:

(defvar *param*) ;; at the top level: define the variable

;; Now actually just a pure assignment in the function now
(defun assign-param (x)
  (setf *param* (generic-funct x)))

我添加了*“耳罩”,因为我无法在良心中引入动态变量而没有;我的好名字附在这个答案上。

真的,为什么呢?为什么隐藏一个功能背后的任务副作用。它几乎肯定更好地记录*param*变量并让调用者自己完成赋值。

在这种访问墙后面包装一个Lisp动态变量只会削弱它。

Lisp让我们这样做:

;; locally re-bind variable
(let ((*param* (some-value)))
  (code)
  ...))

(code)正文将使用*param*执行,其值为(some-value)。当let终止时,无论它如何终止,都会恢复之前的值。变量仍然是全局的:改变的值可以看作是在体内调用的函数内部,而不仅仅是在let中的词法作用域中,与词法变量一样。

*param*这样处理的原因是defvardefparameter形式专门标记了这种类型的绑定和范围的符号。它成为“特殊变量”。这就是为什么我们使用*...*耳罩:创建一个单独的命名空间,大声识别这些非词法范围的变量,防止我们意外地将代码中的词汇变量转换为特殊变量。)

如果我们隐藏*param*的存在,在函数后面,我们会失去这种灵活性;我们把它简化为一个愚蠢的全局,只能通过调用assign-param来破坏。

assign-param函数对我说(即使修复后使用setf在外面使用defvar),“我不理解Lisp,我害怕全局我使用其他语言的经验中的变量“。