关于lisp中使用递归函数的问题

Questions about using recursive functions in lisp

我是口齿不清的初学者。感谢Whosebug对我的帮助。

首先,我想用lisp函数表达递归函数。 没有编译错误,但是我想检查一下我写的代码语法是否正确

下面是我写的C代码

void queens(int i)
{
    int j;
 
    if (promising(i))    
    {
        if (i == n)   
        {
            //print all col list
            return
        }
        else    
        {
            for (j = 1; j <= n; j++)    
            {
                col[i + 1] = j;
                queens(i + 1);
            }
        }
    } 
}

下面是 lisp 代码。

(defvar n 4) 
(defvar col (list 0 0 0 0 0 ))

(defun queens(i)
    (let ((j 1))  
    (if (promising i)  
        (if (= i n) (print col)  
        (loop while (<= j n) do (setf (nth (+ 1 i ) col) j) 
        ( queens (+ 1 i ) ) 
        (incf j)))  
    )
))

首先,您(仍然)需要修复缩进、对齐和一般样式。这不仅是为了惹恼您,还因为它实际上 使事情更清晰,更容易调试。例如,如果缩进不正确,就很难看清每个表达式的结束位置,使用 loop 等复杂宏时情况更糟。您的代码,格式正确但没有任何其他修改,应该是:

(defun queens (i)
  (let ((j 1))
     (if (promising i)  
         (if (= i n)
             (print col)
             (loop while (<= j n)
                   do (setf (nth (+ 1 i) col) j) 
                      (queens (+ 1 i)) 
                      (incf j))))))
  • 右括号紧跟在表达式的最后一个形式之后,没有换行符,没有空格。
  • 左括号也在表格的第一个元素之前,没有空格,但应该与前面的内容分开,除非它是另一个括号(所以(defun queen (i) ...) 是正确的,而 ( defun queens(i)) 违反了两条规则)。
  • 当使用 if 结构时,要么将其写成 all 在一行中(条件、“then”形式和“else”形式) , 或者您必须在每个之后插入换行符。否则,不清楚“then”形式何时结束以及“else”何时开始。
  • 当用 defvar 定义特殊变量时,用 '*' 来命名它们,如 (defvar *n* 4)(defvar *col* (list ...)).

另一个样式注意事项,有助于解决与嵌套相关的问题:如果您只对两个分支之一感兴趣,请使用 whenunless 而不是 if。这使得意图清晰,并且还可以在复杂分支的情况下简化语法。

现在,对于代码: 如果您想使用 loop,请使用基本的 for 结构。而不是写

(loop while (< j n) do ... (incf j))

使用

(loop for j from <start> to <end> do ...)

如果您想要稍微不同的终止条件,也可以使用 upto, below ...。 执行此操作时,不需要使用 letj 引入绑定,它将由循环引入。

如果要修改列表,请改用向量。不要将 col 定义为 (list ...),只需使用 (vector ...)make-array 函数即可。之后,使用 eltaref 访问单个元素,而不是仅适用于列表的 nth。假定已考虑所有先前评论的代码版本:

(defun queens (i)
  (when (promising i)  
    (if (= i n)
        (print *col*)
        (loop for j from 1 to *n*
              do (setf (aref *col* (1+ i)) j)
                 (queens (1+ i))))))

不知道 promising 做什么以及 queens 应该做什么,很难给出更多的见解,但算法仍然很奇怪。例如,在对 (queens i) 的给定调用中,词法上明显的 setf 只会修改 coli+1-th 单元格,将其设置为新的 j在每次迭代中。据我所知,这只会导致 (aref col (1+ i)) 在循环结束时被设置为 n。似乎您也没有使用由 queens 递归地 return 编辑的值(这是意料之中的:您的 C 函数 return 什么都没有!),而且您实际上并没有这样做任何涉及 col 的检查,因此递归解决方案看起来很奇怪,(queens i) 和它在循环中调用 n 次的 (queens (1+ i)) 之间(似乎)没有任何关系!

如果上面的段落无关紧要,因为 promising 也大量修改了 col:停止做 C-in-Lisp 并停止到处修改。如果可以避免,不要依赖状态、突变、全局变量等。很容易定义递归解决方案,将列表作为参数传递给 return 多个值......因此通常不需要使用多个函数,每个函数都调用另一个函数,递归地修改共享的全局状态.乱七八糟,无法调试。