Lisp错误:代码包含一个虚线列表,以。结尾

时间:2018-02-13 03:32:19

标签: lisp common-lisp

尝试计算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)) 

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"

所以,一些评论:

  1. 请避免将新括号放在新行上,就像您可能习惯将花括号放在新行上一样,关闭它们是惯用的#34;所有这些都是"
  2. cond需要一定的括号布局,它总是(cond (condition-1 expression-1) ... (condition-k expression-k)),依此类推。您获得的语法错误是因为违反了此规则;你可以随时lookup basic syntax
  3. 使用builtin increment/decrement operators(+ 1 x)(- 1 x)可以更好地表达次要尼特:(1+ x)(1- x)
  4. 最后,虽然这是一个自然递归函数,并且在您的示例中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采取了绕行"围绕这个漂亮的错误检查,我们得到一个神秘的错误消息。换句话说,它看起来像一个小虫。诊断"的意图应该是一个清单"被意外挫败了。