Filter 使用尾部递归的过滤函数

Filter 使用尾部递归的过滤函数,filter,scheme,racket,Filter,Scheme,Racket,目前我有 (define filter (λ (f xs) (letrec [(filter-tail (λ (f xs x) (if (empty? xs) x (filter-tail f (rest xs) (if (f (first

目前我有

  (define filter
    (λ (f xs)
      (letrec [(filter-tail
                (λ (f xs x)
                  (if (empty? xs)
                      x
                      (filter-tail f (rest xs)
                                        (if (f (first xs))
                                            (cons (first xs) x)
                                            '()
                                            )))))]
        (filter-tail f xs '() ))))
它应该具有过滤功能

然而,它输出为

(filter positive? '(-1 2 3))
>> (3 2)
但是正确的返回应该是(2 3)

我想知道是否使用尾部递归正确地完成了代码,如果是这样,那么我应该使用反向来更改答案

我想知道使用尾部递归是否正确地完成了代码

是的,它使用了正确的尾部调用。你有

(define (filter-tail f xs x) ...)
它在内部递归地应用于

(filter-tail f
             (some-change-to xs)
             (some-other-change-to x))
(filter-tail f xs '())
而且,它在外部应用于

(filter-tail f
             (some-change-to xs)
             (some-other-change-to x))
(filter-tail f xs '())
这两个应用程序都处于尾部位置

我应该用反面来改变答案吗

是的,除非在构建列表时对列表的尾部(而不是头部)进行变异,否则没有办法绕过它。您收到的一条评论使用
set cdr(另请参见:)。可能还有其他技术,但我不知道。我很想听


这是尾部递归,需要反转输出。这一个使用了一个命名let

(define (filter f xs)
  (let loop ([ys '()]
             [xs xs])
    (cond [(empty? xs) (reverse ys)]
          [(f (car xs)) (loop (cons (car xs) ys) (cdr xs))]
          [else (loop ys (cdr xs))])))

(filter positive? '(-1 2 3)) ;=> '(2 3)
这是另一个用左折的。输出仍然需要反转

(define (filter f xs)
  (reverse (foldl (λ (x ys) (if (f x) (cons x ys) ys))
                  '()
                  xs)))

(filter positive? '(-1 2 3)) ;=> '(2 3)
有了技术和技术,我们

这建立了

                   comp
              /            \
           comp           cons1 5
        /        \
     comp       cons1 3
    /     \
  IC     cons1 1
并对其应用
”()
,以高效的从右到左的顺序构造结果列表,因此无需反转它

首先,
fold
通过逐个组合考虑函数,以尾部递归的方式构建结果列表的差异列表表示;然后将生成的函数应用于
”()
,并通过
comp
函数组合定义的优点,再次以尾部递归的方式进行缩减,因为组合函数嵌套在左侧,因为
fold
是一个左折叠,从左到右处理列表:

((IC+k1)+k3)+k5);为“comp”写入“+”`
=>((IC+k1)+k3)(k5’());和'kI'表示`(cons1 I)的结果`
((IC+k1)(k3 l5))
(集成电路(k1-l3))

是的,您需要反转结果。这适用于所有尾部递归吗?是的,除非您编写“反转”过程;-)在添加到累加器时,可以实现一个head-sentinel或tail-modulo-cons,但是在末尾将其反转是解决问题的最直接的方法。列表从开始到结束进行迭代,从结束到结束创建。因此,尾部递归副本将反转输入。