LISP更改本地函数中的全局变量值

时间:2013-09-28 15:44:05

标签: lisp global-variables

我是lisp领域的新手...我正在编写一个代码来解决bfs中的8个难题......

我想将访问列表存储在全局列表中,并定期从函数中更改其值...

(defparameter *vlist* nil)
(defun bfs-core(node-list)
        (let (cur-node tmp-node-list)
            (if (null node-list)
                NIL
                (progn
                ;       (if (= 1 (length node-list)) 
                    (setq cur-node (car node-list))
                    (setq tmp-node-list (cdr node-list))
                    (if (goalp  cur-node)
                        cur-node
                    ((setq *vlist* (append cur-node *vlist*))
                       (bfs-core (append tmp-node-list (expand cur-node))))))
                    )
                )
            )

defparameter one是我的全局变量...并且我想用setq更改其值的函数...我还使用了defvar,setf,set和所有可能的组合...... 任何人都可以帮我解决????

3 个答案:

答案 0 :(得分:1)

您当然可以从内部函数更改全局变量:

[1]> (defparameter *visited-lists* nil)
*VISITED-LISTS*
[2]> *visited-lists* 
NIL
[3]> (defun change-global-value ()
  (setf *visited-lists* (append (list 'new-value) 
                                *visited-lists* )))
CHANGE-GLOBAL-VALUE
[4]> *visited-lists* 
NIL
[5]> (change-global-value) 
(NEW-VALUE)
[6]> *visited-lists* 
(NEW-VALUE)
[7]> (change-global-value) 
(NEW-VALUE NEW-VALUE)
[8]> *visited-lists* 
(NEW-VALUE NEW-VALUE)

但是让我们再看一下你的代码:

(defun bfs-core(node-list)
        (let (cur-node tmp-node-list)
            (if (null node-list)
                NIL
                (progn
                ;       (if (= 1 (length node-list)) 
                    (setq cur-node (car node-list))
                    (setq tmp-node-list (cdr node-list))
                    (if (goalp  cur-node)
                        cur-node
                    ((setq *vlist* (append cur-node *vlist*))
                       (bfs-core (append tmp-node-list (expand cur-node))))))
                    )
                )
            )

首先,让我们在正确的行上得到括号,然后删除注释掉的代码。大多数Lisp程序员不会像ALGOL风格的语言那样关闭他们的大括号:

(defun bfs-core(node-list)
  (let (cur-node tmp-node-list)
    (if (null node-list)
        NIL
      (progn
        (setq cur-node (car node-list))
        (setq tmp-node-list (cdr node-list))
        (if (goalp  cur-node)
            cur-node
          ((setq *vlist* (append cur-node *vlist*))
           (bfs-core (append tmp-node-list (expand cur-node)))))))))

现在,nil的第一个分支有一个if。我们可以将其更改为unless,其中包含内置progn,因此我们也不需要:

(defun bfs-core(node-list)
  (let (cur-node tmp-node-list)
    (unless (null node-list) ;;changed this line to an unless, dropped nil, progn
      (setq cur-node (car node-list))
      (setq tmp-node-list (cdr node-list))
      (if (goalp  cur-node)
          cur-node
        ((setq *vlist* (append cur-node *vlist*))
         (bfs-core (append tmp-node-list (expand cur-node))))))))

我们还使用let将一些变量设置为nil,当我们进入unless时,我们立即将变量设置为我们实际想要工作的值用。让我们切换它,这样我们只有在我们要使用它们时才创建变量:

(defun bfs-core(node-list)
  (unless (null node-list) ;;switched this line and the let below
    (let ((cur-node (car node-list)) ;;also set the variables inside the let
          (tmp-node-list) (cdr node-list))
      (if (goalp  cur-node)
          cur-node
        ((setq *vlist* (append cur-node *vlist*))
         (bfs-core (append tmp-node-list (expand cur-node))))))))

好的,我们已经有了更清晰的代码。耶!

让我们看一下这里的一个电话:

((setq *vlist* (append cur-node *vlist*))
 (bfs-core (append tmp-node-list (expand cur-node))))

你的意思是把它作为单个电话,而不是两个吗?这和它之间有区别:

((setq *vlist* (append cur-node *vlist*)))
(bfs-core (append tmp-node-list (expand cur-node)))

你看到了区别吗?第一个是单一陈述;第二个是两个。您可能想要第二个,因为您想要更改*vlist*,然后拨打bfs-core。而且,要,您需要progn

(defun bfs-core(node-list)
  (unless (null node-list)
    (let ((cur-node (car node-list))
          (tmp-node-list) (cdr node-list))
      (if (goalp  cur-node)
          cur-node
        (progn (setq *vlist* (append cur-node *vlist*))
               (bfs-core (append tmp-node-list (expand cur-node))))))))

答案 1 :(得分:1)

这是您的代码(为标准Lisp样式重新格式化):

(defparameter *vlist* nil)
(defun bfs-core (node-list)
  (let (cur-node tmp-node-list)
    (if (null node-list)
        NIL
        (progn
          ;       (if (= 1 (length node-list)) 
          (setq cur-node (car node-list))
          (setq tmp-node-list (cdr node-list))
          (if (goalp  cur-node)
              cur-node
              ((setq *vlist* (append cur-node *vlist*))
               (bfs-core (append tmp-node-list (expand cur-node)))))))))

您的代码是一个明确的问题。

表单((setq *vlist* ...) (bfs-core ...))最终成为函数调用。当您有(exp1 exp2 exp3)这样的表单时,exp1是一个应用于exp2exp3参数值的函数。您的exp1(setq *vlist* ...),它不会评估某个功能,当然,您从未想过它。

您的代码的重写版本,至少会删除错位的函数调用,是:

(defparameter *vlist* nil)
(defun bfs-core (node-list)
  (let (cur-node tmp-node-list)
    (if (null node-list)
        NIL
        (progn
          ;       (if (= 1 (length node-list)) 
          (setq cur-node (car node-list))
          (setq tmp-node-list (cdr node-list))
          (if (goalp  cur-node)
              cur-node
              (progn
                (setq *vlist* (append cur-node *vlist*))
                (bfs-core (append tmp-node-list (expand cur-node)))))))))

答案 2 :(得分:0)

其他答案是针对当前问题的。作为有关如何更改传递给子例程的变量的值的一般答案,可以将变量作为符号传递:

(defun modify (x)
  (set x 100))

(setq d 1)         => value of d is 1
(modify 'd)        => value of d is 100

因此,要使用按值传递和按引用传递的术语并将其应用于lisp:

(userfunction 'x)  is pass by reference,
(Userfunction x)   is pass by value.