如何在Lisp Works中对包含数字和字母的列表求和

如何在Lisp Works中对包含数字和字母的列表求和,lisp,common-lisp,clisp,Lisp,Common Lisp,Clisp,我试图定义一个以列表为参数的求和函数。问题是我的列表不仅可以包含数字,还可以包含字母。所以我的问题是,我如何避免这些信件,并继续验证列表的其余部分 例:(和)(a 2 4 b d))=6 我只有一个“堆栈溢出”错误 提前感谢。这不是最有效的方法,但请将函数remove if(或delete if)与numberp一起检查。您的代码尝试应用递归方法。在这里,它的格式正确,名称较长: (defun sum (list) (if (numberp (car list)) (sum (

我试图定义一个以列表为参数的求和函数。问题是我的列表不仅可以包含数字,还可以包含字母。所以我的问题是,我如何避免这些信件,并继续验证列表的其余部分

例:(和)(a 2 4 b d))=6

我只有一个“堆栈溢出”错误


提前感谢。

这不是最有效的方法,但请将函数remove if(或delete if)与numberp一起检查。

您的代码尝试应用递归方法。在这里,它的格式正确,名称较长:

(defun sum (list) 
  (if (numberp (car list))
      (sum (cdr list))
      (+ (car list) (sum (cdr list)))))
由于列表为空时未提供基本大小写,因此出现堆栈溢出。 如果将一个NIL列表传递到函数中,会发生什么

  • (汽车列表)
    返回NIL,它不是一个数字
  • 你去别的分店
  • 您尝试将仍然为零的
    (car list)
    添加到递归调用中,以使用同样为零的
    (cdr list)
    求和
  • 现在回到递归调用中的第一步:无止境递归,这最终会触发错误,因为每次调用都会不断分配堆栈帧
  • 因此,您必须定义在给出空列表时发生的情况。 这是一个典型的家庭作业问题。我最喜欢的模板包括
    etypecase
    ,因为它提供了一种防御性的编码方法,可以尽早拒绝错误,并且非常便于阅读:

    (defun foo (list)
      (etypecase list
        (null <base-case>)
        (cons <general-case>)))
    
    这可能是对学生的期望。更好的方法是使用
    endp
    而不是
    null
    ,因为前者检查参数是否有效地是一个列表

    在你的问题中:

    • 基本情况显然返回0
    • 一般情况下,用递归获得的
      cdr
      之和计算
      car
      (如果不是数字,则为零)之和
    但是,您将有一个递归函数,需要在调用堆栈上存储中间结果,这是浪费。为了有一个尾部递归函数,需要将结果和作为函数的参数传递:首先传递0,然后每个递归调用在递归调用自身之前首先计算和。基本大小写返回总和。这保证了在递归调用之间不需要存储中间结果,在正确的情况下(这取决于您的实现),可以将其作为循环进行优化。但由于Common Lisp已经提供了迭代构造,您应该在实践中使用它们:

    (loop for e in list when (numberp e) sum e)
    
    如果您对高阶函数感兴趣,以下操作也可以,但会分配一个中间列表(这是否可接受取决于列表的预期大小):


    你好,谢谢你的解释!我尝试了“cond”方法,但仍然出现错误。我的函数是
    (defun sum(liste)(cond((null liste)nil)((numberp(car liste))(+(car liste)(sum(cdr liste))))((sum(cdr liste))))
    错误消息是“In+of(2 nil)参数应为NUMBER类型”。对于(sum'(2)),空列表的和应为零。在这里,您尝试向nil添加一个未定义的数字。嗨,leo,最后我使用了remove if,它工作得很好!谢谢你们
    (defun foo (list)
      (if (null list)
          <base-case>
          <general-case>))
    
    (loop for e in list when (numberp e) sum e)
    
    (reduce #'+ (remove-if-not #'numberp list))