Recursion 列表的方案和

Recursion 列表的方案和,recursion,lisp,scheme,Recursion,Lisp,Scheme,首先,这是家庭作业,但我只是在寻找一个关于如何做这件事的提示或伪代码 我需要使用递归对列表中的所有项求和。但是,如果在列表中遇到非数字的内容,则需要返回空集。以下是我的尝试: (DEFINE sum-list (LAMBDA (lst) (IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst)))) '() (+ (CAR lst) (sum-list (CDR lst)) )

首先,这是家庭作业,但我只是在寻找一个关于如何做这件事的提示或伪代码

我需要使用递归对列表中的所有项求和。但是,如果在列表中遇到非数字的内容,则需要返回空集。以下是我的尝试:

(DEFINE sum-list
  (LAMBDA (lst)
    (IF (OR (NULL? lst) (NOT (NUMBER? (CAR lst))))
      '()
      (+
        (CAR lst)
        (sum-list (CDR lst))
      )
    )
  )
)

此操作失败,因为它无法将空集添加到其他内容。通常,如果不是数字,我只会返回0并继续处理列表。

尝试创建一个“is any nonnumeric”函数(使用递归);然后你就(或(任何数字列表)(总和列表))愚蠢了。

我建议你使用并返回一个累加器来存储总和;如果在遍历列表时发现非数字,则可以立即返回空列表,否则递归将继续,直到列表用尽为止

沿着这些线的东西(填空!):


你的问题是你需要使用COND,而不是——如果有三个可能的分支需要考虑。第一个是当您遇到一个非数字时,第二个是当您遇到列表的末尾时,第三个是当您需要递归到列表的下一个元素时。第一个问题是,您正在组合非数字大小写和空列表大小写,它们需要返回不同的值。递归的情况基本上是正确的,但是您必须检查返回值,因为递归调用可以返回一个空列表。

因为我不够聪明,无法在一个函数中解决这个问题,让我们痛苦地明确:

#lang racket

; This checks the entire list for numericness
(define is-numeric-list?
  (lambda (lst)
    (cond
      ((null? lst) true)
      ((not (number? (car lst))) false)
      (else (is-numeric-list? (cdr lst))))))

; This naively sums the list, and will fail if there are problems
(define sum-list-naive
  (lambda (lst)
    (cond
      ((null? lst) 0)
      (else (+ (car lst) (sum-list-naive (cdr lst)))))))

; This is a smarter sum-list that first checks numericness, and then
; calls the naive version.  Note that this is inefficient, because the
; entire list is traversed twice: once for the check, and a second time
; for the sum.  Oscar's accumulator version is better!
(define sum-list
  (lambda (lst)
    (cond
      ((is-numeric-list? lst) (sum-list-naive lst))
      (else '()))))

(is-numeric-list? '(1 2 3 4 5))
(is-numeric-list? '(1 2 x 4 5))

(sum-list '(1 2 3 4 5))
(sum-list '(1 2 x 4 5))
输出:

Welcome to DrRacket, version 5.2 [3m].
Language: racket; memory limit: 128 MB.
#t
#f
15
'()
> 
不过,我怀疑你的家庭作业期望的是更学术的东西。

我想:

(define (mysum lst)
  (let loop ((lst lst) (accum 0))
    (cond
      ((empty? lst) accum)
      ((not (number? (car lst))) '())
      (else (loop (cdr lst) (+ accum (car lst)))))))

如果我将非数字大小写和空列表大小写分开,我想为空列表返回0,为非数字返回'()。但是,当调用递归时,它将尝试将空列表添加到它之前积累的内容中,从而产生如下vm异常:(+3’())。我想唯一的方法是使用两个参数。@rem45acp-捕捉良好-在添加当前值之前,您必须检查返回值。如果您不介意不必要地处理列表的其余部分,您可能可以将“当前为非数字”案例和“递归调用返回的非数字”案例结合起来。我喜欢这两个参数的想法,但这真的可以只使用一个参数吗?可以,但我能想到的实际工作的最佳方式需要2个
if
语句和一个
let
。使用双参数版本(可能与一个只调用
(内部函数x 0)
的包装函数一起使用)可能是最好的方法。此外,如果您还遇到了尾部递归,那么双参数版本是尾部递归的,而任何单参数版本都不是。我花了很长时间才弄清楚这一版本是如何工作的,尤其是第二行的双lst。我只能设想一个双参数版本,你可以用(lst2 let)替换(lst lst),并将每次出现的lst更改为低于lst2;这可能会让事情更清楚。基本上,它创建一个局部变量let(或lst2),该变量用原始参数lst的值初始化。
(define (mysum lst)
  (let loop ((lst lst) (accum 0))
    (cond
      ((empty? lst) accum)
      ((not (number? (car lst))) '())
      (else (loop (cdr lst) (+ accum (car lst)))))))