使用 Scheme,如何在递归调用(嵌套列表)期间保持变量的值?

Using Scheme, how to keep a variable's value during recursive calls (nested lists)?

我试图从列表中删除最后一次出现的值,但我的程序在使用嵌套列表进行递归调用时失败了。

我有一个计算符号出现次数的函数:

(define (countOccurrences lst elem count)
  (cond
    [(empty? lst)            count]
    [(list? (car lst))       (countOccurrences (cdr lst) elem
                                         (countOccurrences (car lst) elem count))]
    [(equal? (car lst) elem) (countOccurrences (cdr lst) elem (add1 count))]
    [else                    (countOccurrences (cdr lst) elem count)]))

主体在这里:

(define (lastLess lst elem)
  (let ((count (countOccurrences lst elem 0)))
    (if (< 0 count)
        (lastLessHelper lst elem count)
        lst)))

辅助函数:

(define (lastLessHelper lst elem count)
  (cond
    [(empty? lst)         empty]
    [(eq? count 0)        (cdr lst)]
    [(eq? (car lst) elem) (set! count (sub1 count))
                          (cond
                            [(eq? count 0) (cdr lst)]
                            [else          (cons (car lst)
                                                 (lastLessHelper (cdr lst) elem count))])]
    [(list? (car lst))    (cons (lastLessHelper (car lst) elem count)
                                (lastLessHelper (cdr lst) elem count))]
    [else                 (cons (car lst) (lastLessHelper (cdr lst) elem count))]))

问题出在这一行:

[(list? (car lst)) (cons (lastLessHelper (car lst) elem count) (lastLessHelper (cdr lst) elem count))]

每当 (car lst) 等于 elem 时,我都会递减 'count' 变量,并且在第一次递归调用期间 (lastLessHelper (car lst) elem count) 它会正确递减,但是当调用 returns 并且它在 cdr lst 上递归:(lastLessHelper (cdr lst) elem count))] 'count' returns 的值到它的原始值。

它适用于普通列表输入,例如 (lastLess '(1 2 3 2 4 5) '2)) 我正确地得到 (1 2 3 4 5),但是当使用嵌套列表作为输入时,例如 (lastLess '(1 (2 3) 4 2 5) '2) 它 returns (1 (2 3) 4 2 5)

如何在递归调用中保持'count'的值?我应该注意,可能有更简单的方法来做到这一点,但这是一项家庭作业,我们被禁止使用 'reverse' 调用。

编辑:Sylwester 的评论帮助我理解了。我的问题不是计算某个项目的出现次数,而是删除最后一次出现的项目。我的想法是首先计算该项目的出现次数,然后遍历列表并将该计数递减直到它为 0,然后我就会知道删除该项目,然后只 cons 列表的其余部分。

您永远不需要使用 set!

(define (count-matches needle haystack)
  ;; helper
  (define (count-matches count haystack)
    (cond ((equal? needle haystack) (+ count 1))
          ((pair? haystack)
           (count-matches (count-matches count (car haystack))
                          (cdr haystack)))
          (else count)))

  ;; call helper
  (count-matches 0 haystack))

(count-matches 2 '(1 (2 3) 4 2 5)) ; ==> 2

如您所见,我们在 car 的递归中使用 count 并在 cdr 的递归中使用 return 值作为 count .

您甚至 不需要 计数器变量或辅助过程,只需 return 每个部分结果,然后累积递归调用的子结果。试试这个,使用遍历列表列表的标准模板:

(define (count-matches ele lst)
  (cond ((null? lst)                ; if the list is empty
         0)                         ; return default value
        ((not (pair? lst))          ; if this is a single element
         (if (equal? lst ele) 1 0)) ; check if it matches
        (else                       ; otherwise accumulate results of
         (+ (count-matches ele (car lst))     ; the `car` part
            (count-matches ele (cdr lst)))))) ; and the `cdr` part

例如:

(count-matches 'x '(1 (x 2) 3 x (4 (5 x)) 6 (x)))
=> 4