lisp的新手,编译器告诉我这是一个糟糕的lambda

时间:2015-09-30 02:24:45

标签: lambda lisp common-lisp

我是lisp的新手,在我大学生涯的这一点上对lambda表达的经验很少。这是一个带有问题的家庭作业练习:

  
      
  1. 编写一个LISP函数COUNTALLNUMBERS,它计算列表中数字原子的数量,无论它们的嵌套程度如何。例如:   (COUNTALLNUMBERS'(1 A 2(3 B 4(5 6))))   返回值6
  2.   

我正在使用Lispworks编译我的代码并且一直收到错误:

 Badly formed lambda: (NUMBERP (CAR LIST) (+ 1 (COUNTALLNUMBERS (CDR LIST))))

这是我的代码:

(defun countallnumbers(list)
  (if (eql list nil)
      nil 
    (let ((elem (car list))
          (restlist (cdr list)))
      (if (listp elem)
          (append (countallnumbers elem) (countallnumbers restlist))
        (append (cons elem nil) (countallnumbers restlist)))
      ((numberp (car list) (+ 1 (countallnumbers (cdr list))))))))

(write (countallnumbers '(1 2 3 a b (4 c))))

到目前为止,我已经测试并通过调用numberp来完成所有工作。我认为如果将输入转换为原子列表而不是嵌套,那么处理所有内容是最容易的。任何帮助理解这一点将不胜感激

2 个答案:

答案 0 :(得分:4)

语法错误在:

((numberp (car list) (+ 1 (countallnumbers(cdr list)))))

因为,根据你的程序,这个列表被读作一个表单,它的第一个元素应该是一个符号函数或一个lambda列表(即(lambda (args) body)),其余的是这个函数的参数。另一方面,如果您将此作为要评估的条件(给定谓词numberp),则将其写入if形式之外,该形式仅具有条件(与{{不同) 1}})。

你的函数有一个主要问题:它应该返回一个数字,但是当输入是一个空列表(结果应该是cond,而不是0)时,你正在返回列表在其他情况下通过nil

还有其他一些小风格问题:

  1. 测试空列表的常用方法是append,而不是(endp list)
  2. 封闭的括号不应单独写在一行。
  3. 以下是该功能的可能定义:

    (eql list nil)

    请注意,使用(defun countallnumbers(list) (cond ((endp list) 0) ((numberp (car list)) (1+ (countallnumbers (cdr list)))) ((listp (car list)) (+ (countallnumbers (car list)) (countallnumbers (cdr list)))) (t (countallnumbers (cdr list))))) 代替cond,因为必须检查四种情况:当列表为空时,汽车是数字,或者是列表,或者它既不是数字也不是清单。在所有情况下,都会返回一个整数,包括终止情况,列表为空时以及递归情况。 if是向其参数添加1的函数,同时请注意,在1+是列表的情况下,通过添加计数的汽车数量来获得结果列表的cdr号码。

答案 1 :(得分:2)

  1. 按照老师的说法做,但要注意教科书要求你写出丑陋的功能名称。我在这里写count-all-numbers(人们很少写#34; LISP",但" Lisp")。

  2. 列表评估对第一个元素的处理方式与其他元素不同。它应该是一个特殊的运算符或函数指示符:在当前环境中为fboundp的符号或文字(lambda ...)形式。 (numberp ...)既不是,也是常规列表。这就解释了为什么你会收到错误。

  3. 使用工具格式化代码(emacs / paredit)。如果你没有,你仍然可以在引用的函数中使用pprint来查看表达式通常是如何格式化的(仍然有机会以更加人性化的方式布局代码)。 结果很可能是大写的。我通常将*print-circle*绑定到:downcase,如下所示:

    (let ((*print-circle* :downcase))
      (pprint '(defun ...)))
    
  4. 最简单的递归解决方案是:

    (defun count-all-numbers (form)
       (typecase form
         (cons (+ (count-all-numbers (car form))
                  (count-all-numbers (cdr form))))
         (number 1)
         (t 0)))
    

    可以采用更有效的方法来做到这一点,但在此问题开始成为问题之前,您必须处理非常大的列表。