Lisp错误:LET绑定规范格式错误

时间:2018-10-23 23:20:28

标签: lisp common-lisp sbcl clisp

我真的对普通Lisp陌生并且有些挣扎。我正在使用给定 x y array 且垂直值索引返回 NIL 的函数>如果(xy)中有对角线元素。

(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
)

但是,当我尝试使用此功能时,出现以下错误:

; 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))

2 个答案:

答案 0 :(得分:11)

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

(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需要绑定列表。单个绑定是变量或(variable value)

(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不是数字。 =已返回TNIL,我们可以对其进行测试。

(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)

第五:return T不是有效的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不需要col,我们可以在FOR中用另一个LOOP替换它。

(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)

摘要:for from 0 to n可以替换为below (+ n 1)upto 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的函数返回,因此我们可以在循环中将其替换为UNTIL子句:

(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的建议,使用NEVERLOOP的默认返回值现在为T。当nil子句失败时,仅返回never

(defun diagonal? (x y array)
  (loop for line below 20
        for col across array
        until (= col -1)
        never (= (abs (- x line))
                 (abs (- y col)))))

答案 1 :(得分:6)

根据CLHSlet具有以下结构:

(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)))
  ...)

我还注意到您在(的同一行上,就像在制作一个方块一样。由于((if ....))不是有效的Common Lisp代码,因此无法使用。您收到错误,即运算符应为命名函数或lambda。 let是一个块,因此起始(let ...)构成了一个块,因此您可以在其中包含许多表达式而无需附加括号。