Recursion 方案尾递归

Recursion 方案尾递归,recursion,scheme,tail-recursion,tailrecursion-modulo-cons,Recursion,Scheme,Tail Recursion,Tailrecursion Modulo Cons,我试图创建一个scheme-tail递归函数flatte tl rec,用于展平嵌套列表 (define flatten-tl-rec (lambda (xs) (letrec ([flatten-tl-rec-acc (lambda (xs acc) (cond ((empty? xs) acc) ((list? (first xs)) (flatten-tl-rec-acc (

我试图创建一个scheme-tail递归函数flatte tl rec,用于展平嵌套列表

(define flatten-tl-rec
  (lambda (xs)
    (letrec ([flatten-tl-rec-acc
              (lambda (xs acc)
                (cond ((empty? xs) acc)
                      ((list? (first xs)) (flatten-tl-rec-acc (rest xs) (append (flatten-tl-rec-acc (first xs) '()) acc)))
                      (else (flatten-tl-rec-acc (rest xs) (cons (first xs) acc))))
                )])
      (flatten-tl-rec-acc xs '()))))

(flatten-tl-rec '(1 2 3 (4 5 6) ((7 8 9) 10 (11 (12 13))))) 
但是我得到的是
(13 12 11 10 9 8 7 6 5 4 3 2 1)
,而不是
(1 2 3 4 5 6 8 9 10 11 13)

这里出了什么问题?

您在列表的错误端累积元素。您可以将它们附加到列表的正确末尾:

(define flatten-tl-rec
  (lambda (xs)
    (letrec ([flatten-tl-rec-acc
              (lambda (xs acc)
                (cond ((empty? xs) acc)
                      ((list? (first xs))
                       (flatten-tl-rec-acc
                        (rest xs)
                        (append acc (flatten-tl-rec-acc (first xs) '()))))
                      (else (flatten-tl-rec-acc
                             (rest xs)
                             (append acc (list (first xs)))))))])
      (flatten-tl-rec-acc xs '()))))
。。。或者简单地将列表倒过来:

(define flatten-tl-rec
  (lambda (xs)
    (letrec ([flatten-tl-rec-acc
              (lambda (xs acc)
                (cond ((empty? xs) acc)
                      ((list? (first xs))
                       (flatten-tl-rec-acc
                        (rest xs)
                        (append (flatten-tl-rec-acc (first xs) '()) acc)))
                      (else (flatten-tl-rec-acc
                             (rest xs)
                             (cons (first xs) acc)))))])
      (reverse (flatten-tl-rec-acc xs '())))))

更大的问题是,该函数根本不是尾部递归的:它对自身进行的调用并非都处于尾部位置。而是这样做:

(define (flatten xs)
  (let ((result (list 1)))
    (let loop ((xs xs) (p result))
      (cond 
        ((null? xs) 
          (cdr result))
        ((pair? (car xs))
          (loop (cons (caar xs) 
                  (cons (cdar xs) (cdr xs)))
                p))
        ((null? (car xs))
          (loop (cdr xs) p))
        (else
          (set-cdr! p (list (car xs)))
          (loop (cdr xs) (cdr p)))))))
这通过手工实现了优化,使用了“headsentinel”技巧,大大简化了代码,只需分配一个额外的cons单元