Lisp中出错:LET绑定规范格式不正确

Lisp中出错:LET绑定规范格式不正确,lisp,common-lisp,sbcl,clisp,Lisp,Common Lisp,Sbcl,Clisp,我对普通口齿不清真的是个新手,还有些挣扎。我正在研究一个函数,该函数给定x,y和一个数组,如果(x y)中有对角元素,则该数组的垂直值索引返回NIL 但是,当我尝试此函数时,会出现以下错误: ; caught ERROR: ; The LET binding spec (AREF ARRAY LINE) is malformed. ; (SB-INT:NAMED-LAMBDA DIAGONAL? ; (X Y ARRAY) ; (BLOCK DIAGON

我对普通口齿不清真的是个新手,还有些挣扎。我正在研究一个函数,该函数给定xy和一个数组,如果(x y)中有对角元素,则该数组的垂直值索引返回NIL

但是,当我尝试此函数时,会出现以下错误:

; caught ERROR:
;   The LET binding spec (AREF ARRAY LINE) is malformed.

;     (SB-INT:NAMED-LAMBDA DIAGONAL?
;         (X Y ARRAY)
;       (BLOCK DIAGONAL?
;         (LOOP FOR LINE FROM 0 TO 19
;               DO (LET (COL #)
;                    (# #)))
;         RETURN
;         T))
根据a
的要求,let
具有以下结构:

(let (var  (var2 expression))
  body ...)
这里第一个绑定没有值,但与写入相同:

(let ((var nil) (var2 expression))
  body ...)
您的绑定如下所示:

(let (col                  ; col initialized to nil OK
     (aref array line))    ; variable aref initialized to?
 ...)
变量
aref
应该只有一个表达式。事实上,你似乎缺少一套亲子关系,让它看起来有点像Clojure。也许应该是:

(let ((col (aref array line)))
  ...)

我还注意到,如果您正在生成块,则在同一行上有一个
)。这不起作用,因为
((如果…)
不是有效的公共Lisp代码。您会得到一个错误,即运算符应该是命名函数或lambda。
let
是一个块,因此start
(let…)
生成一个块,这样您就可以在块中有许多表达式,而不需要额外的括号。

首先也是非常重要的一点:使用自动缩进

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let (col (aref array line)) (
                                      (if (= col -1) (return-from diagonal? t))
                                      (let (diag (= (abs (- x line)) (abs (- y col)))) (
                                                                                        if (= diag T) (return-from diagonal? NIL))
                                        )
                                      )))
  return T
  )
然后,您的代码在长行中看起来很奇怪:永远不要在自己的行上放括号,也不要在行的末尾放一个开括号

改进:

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let (col (aref array line))
          ((if (= col -1)
               (return-from diagonal? t))
           (let (diag (= (abs (- x line))
                         (abs (- y col))))
             (if (= diag T)
                 (return-from diagonal? NIL))))))
  return T)
第二:
LET
需要一个绑定列表。单个绑定是一个变量或
(变量值)

第三:我们需要一个Lisp表单体。即零个或多个Lisp表单:

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let ((col (aref array line)))
          (if (= col -1)
               (return-from diagonal? t))
          (let ((diag (= (abs (- x line))
                         (abs (- y col)))))
            (if (= diag T)
                (return-from diagonal? NIL)))))
  return T)
第四:
=
需要数字作为参数。
T
不是一个数字。
=
已经返回了
T
NIL
,我们可以测试它

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let ((col (aref array line)))
          (if (= col -1)
              (return-from diagonal? t))
          (if (= (abs (- x line))
                 (abs (- y col)))
              (return-from diagonal? NIL))))
  return T)
第五:
returnt
不是有效的Lisp表单。我们可以直接返回
T

(defun diagonal? (x y array)
  (loop for line from 0 to 19 do
        (let ((col (aref array line)))
          (if (= col -1)
              (return-from diagonal? t))
          (if (= (abs (- x line))
                 (abs (- y col)))
              (return-from diagonal? NIL))))
  T)
第六:对于
,我们不需要
LET
,我们可以在
循环
中用另一个
替换它

(defun diagonal? (x y array)
  (loop for line from 0 to 19
        for col = (aref array line)
        do
        (if (= col -1)
            (return-from diagonal? t))
        (if (= (abs (- x line))
               (abs (- y col)))
            (return-from diagonal? NIL))))
  T)
第七:多个
IF
可以作为单个
COND
写入

(defun diagonal? (x y array)
  (loop for line from 0 to 19
        for col = (aref array line)
        do (cond ((= col -1)
                  (return-from diagonal? t))
                 ((= (abs (- x line))
                     (abs (- y col)))
                  (return-from diagonal? nil))))
  t)
Eigth:
对于从0到n的值
可以替换为
以下(+n1)
最多n的值

(defun diagonal? (x y array)
  (loop for line below 20
        for col = (aref array line)
        do (cond ((= col -1)
                  (return-from diagonal? t))
                 ((= (abs (- x line))
                     (abs (- y col)))
                  (return-from diagonal? nil))))
  t)
第九:由于
(RETURN-FROM…T)
从默认情况下显式返回
T
的函数返回,因此我们可以在循环中用
直到
子句替换它:

(defun diagonal? (x y array)
  (loop for line below 20
        for col = (aref array line)
        until (= col -1)
        when (= (abs (- x line))
                (abs (- y col)))
        do (return-from diagonal? nil))
  t)
第十:因为col只是数组值的迭代:

(defun diagonal? (x y array)
  (loop for line below 20
        for col across array
        until (= col -1)
        when (= (abs (- x line))
                (abs (- y col)))
        do (return-from diagonal? nil))
  t)
第十一:由@Coredump建议,使用
NEVER
循环的默认返回值现在是
T
。只有
NEVER
子句失败时,才返回
nil

(defun diagonal? (x y array)
  (loop for line below 20
        for col across array
        until (= col -1)
        never (= (abs (- x line))
                 (abs (- y col)))))
第十一,使用“从不”而不是“返回”?
(defun diagonal? (x y array)
  (loop for line below 20
        for col across array
        until (= col -1)
        when (= (abs (- x line))
                (abs (- y col)))
        do (return-from diagonal? nil))
  t)
(defun diagonal? (x y array)
  (loop for line below 20
        for col across array
        until (= col -1)
        never (= (abs (- x line))
                 (abs (- y col)))))