函数参数如何存储在lisp中?

时间:2013-10-16 15:15:20

标签: function parameters lisp common-lisp

我假设传递给lisp函数的值被分配给与参数名称匹配的引用。但是,我对此感到惊讶:

(defun test (x) (print (eval 'x)))
(test 5)

不起作用(变量x未绑定)。因此,如果参数未作为符号存储在函数中,那么本例中究竟是什么IS?有没有办法从符合参数名称的符号访问参数?

更多背景信息: 我想做的是这样的事情:

defun slice (r1 c1 r2 c2 board)
  (dolist (param '(r1 c1 r2 c2))  ;adjust for negative indices
    (if (< (eval param) 0)
      (set param (+ (length board) (eval param)))))
        ;Body of function

基本上,我想迭代前四个参数并调整它们的任何值,如果它们是&lt; 0.当然,我可以做一个let并为每个参数设置一条单独的行,但考虑到我对四个参数中的每个参数都做了同样的事情,这看起来更清晰。 但是,我得到变量R1未绑定的错误。

3 个答案:

答案 0 :(得分:5)

这基本上是词法绑定的工作原理:变量名在词法范围内被替换,直接引用变量值的存储位置。绑定变量名symbol-value仅对动态变量进行,您可以使用special声明该变量。

避免重复自己的一种方法是宏:

(defmacro with-adjusting ((&rest vars) adjust-value &body body)
  `(let ,(loop for var in vars
               collect `(,var (if (minusp ,var)
                                (+ ,var ,adjust-value)
                                ,var)))
     ,@body))

(defun slice (r1 c1 r2 c2 board)
  (with-adjusting (r1 c1 r2 c2) (length board)
    ;; function body

答案 1 :(得分:4)

  

有没有办法从符合参数名称的符号中访问参数?

不适用于词法绑定。 Common Lisp无法从类似的命名符号访问词法变量。您需要声明变量 special

  

因此,如果参数未作为符号存储在函数中,那么本例中究竟是什么IS?

处理器注册?堆栈框架的一部分?

使用动态绑定:

CL-USER 40 > (defun foo (a b)
               (declare (special a b))
               (dolist (v '(a b))
                 (if (zerop (symbol-value v))
                     (set v 10)))
               (values a b))
FOO

CL-USER 41 > (foo 1 0)
1
10

答案 2 :(得分:2)

正如Rainer所解释的那样,你无法通过名称来访问词法参数值。

如果您还想要变量,那么您可以使用&rest参数和destructuring-bind

(defun slice (board &rest params)
  (destructuring-bind (r1 c1 r2 c2)
      (mapcar (lambda (param) ;adjust for negative indices
                (if (minusp param)
                    (+ (length board) param)
                    param))
              params)
    ... operate on r1 c1 r2 c2 ...))