如何管理方案中关于添加和计数的任意列表

How to manage arbitrary list in scheme in regard to adding and counting numbers

所以我已经创建了基本功能

(define (countNumbers lst)
 (cond
 ((null? lst) 0)
 ((number? (car lst))(+ 1 (countNumbers (cdr lst))))
 (else (countNumbers (cdr lst)))))

(define (sumNumbers lst)
 (cond
 ((null? lst) 0)
 ((number? (car lst))(+ (car lst) (sumNumbers (cdr lst))))
 (else (sumNumbers (cdr lst)))))

现在有没有办法,你如何让这些函数适用于任意列表,就像我传入 (1 (2 (3))) 给 countNumbers it returns 3 如果我把它传入sumNumbers 它 returns 6?

您可以只添加第二级递归,如下所示:

(define (countNumbers lst)
  (cond
   ((null? lst) 0)
   ((number? (car lst))(+ 1 (countNumbers (cdr lst))))
   ((list? (car lst)) (+ (countNumbers (car lst)) (countNumbers (cdr lst))))
   (else (countNumbers (cdr lst)))))

(define (sumNumbers lst)
  (cond
   ((null? lst) 0)
   ((number? (car lst))(+ (car lst) (sumNumbers (cdr lst))))
   ((list? (car lst)) (+ (sumNumbers (car lst)) (sumNumbers (cdr lst))))
   (else (sumNumbers (cdr lst)))))

这与 有关。本质上,你只需要应用标准模板来遍历列表列表,根据问题做适当的事情:

  1. 测试 null? 列表,基本情况。
  2. 测试当前元素是否为 pair?,在这种情况下,我们必须重复 carcdr 并组合答案。
  3. 否则,我们在一个原子中。

此外,对于您提到的功能,我们必须测试另一种情况:如果当前原子是或不是 number?;而这里合并的方式是将结果相加。例如:

(define (countNumbers lst)
  (cond ((null? lst) 0)
        ((pair? lst)
         (+ (countNumbers (car lst))
            (countNumbers (cdr lst))))
        ((number? lst) 1)
        (else 0)))

(define (sumNumbers lst)
  (cond ((null? lst) 0)
        ((pair? lst)
         (+ (sumNumbers (car lst))
            (sumNumbers (cdr lst))))
        ((number? lst) lst)
        (else 0)))

它按预期工作:

(countNumbers '(1 x (x 2) x (3 (4 x (5) 6) 7)))
=> 7

(sumNumbers '(1 x (x 2) x (3 (4 x (5) 6) 7)))
=> 28

更高层次的抽象

与其使用起源于 IBM 704 机器指令的较低级别的运算符 carcdrcountNumbers 可以在更高的抽象级别上实现使用 function composition and sequences as conventional interfaces as described in The Structure and Interpretation of Computer Programs:

(define (countNumbers lox)
  (length (filter number? (flatten lox))))

实施展平

flatten是一个常见的列表操作。但它不包括在方案标准中。

来自 Rosetta Code:

 (define (flatten x)
    (cond ((null? x) '())
          ((not (pair? x)) (list x))
          (else (append (flatten (car x))
                        (flatten (cdr x))))))

flatten 中内置的 #lang racketsource 提供了基于迭代和 cons:

的更快实现
(define (flatten orig-sexp)
  (let loop ([sexp orig-sexp] [acc null])
    (cond [(null? sexp) acc]
      [(pair? sexp) (loop (car sexp) (loop (cdr sexp) acc))]
      [else (cons sexp acc)])))

在 R5RS 方案中,这将是:

(define (flatten orig-sexp)
  (letrec 
      ((loop (lambda (sexp acc)
               (cond ((null? sexp) acc)
                     ((pair? sexp)
                      (loop (car sexp)
                            (loop (cdr sexp) acc)))
                     (else (cons sexp acc))))))
    (loop orig-sexp '())))