1

我是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 一个是我的全局变量......我想用 setq 更改它的值的函数......我还使用了 defvar、setf、set 和所有可能的组合......有人能帮我吗? ??

4

3 回答 3

2

这是您的代码(重新格式化为标准 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的 is(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)))))))))
于 2013-09-29T16:10:39.187 回答
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)))))))))

现在,我们有了 anil的第一个分支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))))))))

我们还使用 alet将一些变量设置为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))))))))
于 2013-09-28T18:42:46.733 回答
1

其他答案是针对手头的问题的。作为关于如何更改传递给子例程的变量值的一般答案,如果变量作为符号传递是可能的:

(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.
于 2019-08-13T16:04:11.160 回答