How to order my accumulate variable in this case on Racket?

北城以北 提交于 2019-12-02 04:47:27

Of course you can do it without the iter procedure ...

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

But I assume you're using that to keep your add-even procedure tail-recursive. If that's the case then ...


Your accu can be a procedure (instead of a list) which fills in a "hole" in your cons chain. Instead of returning accu at the end of the computation, you fill in the last value, which in this case is empty and initialize with identity instead.

I used bolding to show the parts of your code I changed

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

So now you get tail-recursion and you build the list in forward order. I encourage you to step thru the evaluation of this to see how it works. This is continuation passing style.


And perhaps the procedure would be better if you renamed the vars a little bit

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

And it cleans up even a little more if you used a 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)

... And it cleans up even more if we used compose and 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)

In Racket, built-in for/list with #:when clause can also be used to create a short function:

(define (onlyeven lst)
  (for/list ((i lst) #:when (even? i))
    i))

(onlyeven '(1 2 3 4 5 6 7))
; => '(2 4 6)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!