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

时间:2015-09-13 18:01:41

标签: recursion scheme

我试图从列表中删除最后一次出现的值,并且在使用嵌套列表的递归调用期间我的程序失败。

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

(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))]

我递减计数&#39;变量(car lst)等于elem时,并且在第一次递归调用(lastLessHelper (car lst) elem count)期间它会正确递减,但是当该调用返回并且它在cdr lst上递归时:(lastLessHelper (cdr lst) elem count))] &#39; count&#39;的价值返回原始值。

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

如何保持&#39;计数&#39;在递归调用期间?我应该注意,有可能更简单的方法来做到这一点,但这是一个家庭作业,我们被禁止使用“反向”#39;调用

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

2 个答案:

答案 0 :(得分:2)

您永远不需要使用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

如您所见,我们在count中使用car进行递归,并在count的递归中使用返回值作为cdr

答案 1 :(得分:1)

你甚至不需要计数器变量或帮助程序,只需返回每个部分结果并累积递归调用的子结果。试试这个,使用标准模板遍历列表列表:

(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