尝试计算B ^ e并得到奇怪的错误
*** - code contains a dotted list, ending with B
代码:
(defun fast-power (B e)
(cond(zerop e) B
(t (fast-power(* B B)(- e 1)))
)
)
(write(fast-power 6 3))
答案 0 :(得分:2)
不想"做作业",但这里有多个问题,但你可能想要这样的事情:
(defun fast-power (B e)
(cond
((zerop e) 1)
(t (* B (fast-power B (1- e))))))
(print (fast-power 6 3))
;; Should show "216"
(print (fast-power 3 6))
;; Should show "729"
所以,一些评论:
cond
需要一定的括号布局,它总是(cond (condition-1 expression-1) ... (condition-k expression-k))
,依此类推。您获得的语法错误是因为违反了此规则;你可以随时lookup basic syntax。(+ 1 x)
和(- 1 x)
可以更好地表达次要尼特:(1+ x)
和(1- x)
。fast-power
正文中存在fast-power
表明这一点,但原始示例在基本条件(当e
为0时返回值应为1)和递归步骤(您希望将B
乘以" {{1}的下一个较低值" }})。答案 1 :(得分:2)
正确使用cond
:
(cond
(predicate consequent ...)
(predicate consequent ...)
(t alternative))
请注意,所有字词都是列表。再看一下你的代码:
(cond
(zerop e) ; if the variable zerop is true, then evalaute e
B ; not a correct term! this will fail!
(t (fast-power (* B B) (- e 1)))) ; an ok alternative
答案 2 :(得分:1)
在Common Lisp中,正确的列表由零个或多个cons单元组成,终止nil
。原子nil
本身是一个零长度的正确列表。
不正确的列表是由nil
以外的原子终止的列表。
在某些情况下,除了nil之外的原子本身,被认为是一个列表。
例如,看看:我们可以使用(1 2 3)
附加正确的列表4
,这有效地表现为长度为0的不正确列表:
(append '(1 2 3) 4) -> (1 2 3 . 4)
许多标准库函数被定义为仅在适当的列表上工作。例如mapcar
。看看当我们输入mapcar
数字4而不是列表时会发生什么:
[3]> (mapcar #'identity 4)
*** - MAPCAR: A proper list must not end with 4
错误消息实际上是说,是的,我们确实传了一个列表,但它是一个以4结尾的不正确列表! 因此,如果您没有将4视为以4结尾的零长度列表,则错误消息会让您感到困惑。
结果是如果你给你的Lisp实现一些错误的语法,就会发生这种令人困惑的错误信息。 Lisp系统并不总是通过相关诊断提供对错误语法的完美分析。有时候会发生的是在语法的某些位置预期列表表达式,并且该语法的一部分被盲目地输入到处理它的某个函数中;如果原子代替列表,则会出现一条神秘的错误消息。
E.g。我们可以在我们自己的宏中说明这一点:
[1]> (defmacro user-unfriendly-let (bindings &body form)
(let ((vars (mapcar #'car bindings)))
;; et cetera
))
USER-UNFRIENDLY-LET
这里,我们的user-unfriendly-let
宏期望bindings
参数是一个列表。它盲目地将它提供给mapcar
函数而不进行任何错误检查。所以我们得到:
[2]> (user-unfriendly-let ((a 3)) a) ;; okay
NIL
[3]> (user-unfriendly-let a a) ;; oops confusing error!
*** - MAPCAR: A proper list must not end with A
通常Lisp系统中的标准宏具有良好的错误报告功能;但有时候事情会被忽略,并且通过较低级别的函数检测到错误,因为语法错误会导致意外数据。
用户定义的宏在这方面的质量会有很大差异。这取决于程序员对宏观及其预期用途和受众的态度。
您所看到的行为是CLISP所特有的。请注意,当我们提交格式错误的cond
进行即时评估与将其放入函数时之间存在差异:
$ clisp -q
[1]> (cond B)
*** - COND: clause B should be a list
The following restarts are available:
ABORT :R1 Abort main loop
Break 1 [2]>
[3]> (lambda () (cond B))
*** - code contains a dotted list, ending with B
The following restarts are available:
ABORT :R1 Abort main loop
Break 1 [4]>
所以你看到CLISP cond
运算符本身确实有一个不错的诊断:clause B should be a list
。但不知何故,由于在函数体中处理cond
的方式,CLISP采取了绕行"围绕这个漂亮的错误检查,我们得到一个神秘的错误消息。换句话说,它看起来像一个小虫。诊断"的意图应该是一个清单"被意外挫败了。