我真的对普通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))
答案 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
不是数字。 =
已返回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)
第五: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的建议,使用NEVER
。 LOOP
的默认返回值现在为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)
根据CLHS,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)))
...)
我还注意到您在(
的同一行上,就像在制作一个方块一样。由于((if ....))
不是有效的Common Lisp代码,因此无法使用。您收到错误,即运算符应为命名函数或lambda。 let
是一个块,因此起始(let ...)
构成了一个块,因此您可以在其中包含许多表达式而无需附加括号。