出于教育原因,我正在用Racket编码。
给我一个任务,在该任务中,我应该创建一个不带过滤器的函数,该函数将接收一个列表作为输入,并仅使用第一个列表的偶数返回另一个列表。
我想出了一个迭代过程的递归定义:
(define (add-even lista)
(define (iter lista accu)
(cond ((null? lista) accu)
((even? (car lista)) (iter (cdr lista)
(cons (car lista) accu)))
(else (iter (cdr lista) accu))))
(iter lista empty))
它工作正常。但是,我得到的结果却是相反的顺序,例如:
(add-even '(1 2 3 4 5 6 7))
>> '(6 4 2)
我应该怎么做才能使输出的外观与输入顺序相同?
我知道如何使用反向功能。但这不是一种非常有效的方法。
当然,您无需进行操作即可iter
...
(define (add-even lista)
(cond ((null? lista) empty)
((even? (car lista)) (cons (car lista) (add-even (cdr lista))))
(else (add-even (cdr lista)))))
(add-even '(1 2 3 4 5 6 7))
; => '(2 4 6)
但是我认为您正在使用它来使add-even
过程保持尾部递归。如果是这样的话...
您accu
可以是一个过程(而不是列表),该过程填补了cons
链中的“空洞” 。而不是accu
在计算结束时返回,而是填写最后一个值,在本例中为,empty
并使用进行初始化identity
。
我使用粗体显示了更改的代码部分
(define (add-even lista)
(define (iter lista accu)
(cond ((null? lista) (accu empty))
((even? (car lista)) (iter (cdr lista)
(λ (rest) (accu (cons (car lista) rest)))))
(else (iter (cdr lista) accu))))
(iter lista identity))
(add-even '(1 2 3 4 5 6 7))
; => '(2 4 6)
因此,现在您可以进行尾递归,并且可以按向前的顺序构建列表。我鼓励您逐步对此进行评估,以了解其工作原理。这是延续过去的风格。
如果您稍微重命名vars,也许程序会更好
(define (add-even lista)
(define (iter l k)
(cond ((null? l) (k empty))
((even? (car l)) (iter (cdr l)
(λ (rest) (k (cons (car l) rest)))))
(else (iter (cdr l) k))))
(iter lista identity))
(add-even '(1 2 3 4 5 6 7))
; => '(2 4 6)
如果您使用 named-let
(define (add-even lista)
(let iter [(l lista) (k identity)]
(cond ((null? l) (k empty))
((even? (car l)) (iter (cdr l)
(λ (rest) (k (cons (car l) rest)))))
(else (iter (cdr l) k)))))
(add-even '(1 2 3 4 5 6 7))
; => '(2 4 6)
......即使它清理更多,如果我们使用compose
和curry
(define (add-even lista)
(let iter [(l lista) (k identity)]
(cond ((null? l) (k empty))
((even? (car l)) (iter (cdr l) (compose k (curry cons (car l)))))
(else (iter (cdr l) k)))))
(add-even '(1 2 3 4 5 6 7))
; => '(2 4 6)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句