简体   繁体   English

如何在Racket上订购我的累积变量?

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

I am coding with Racket for educational reasons. 出于教育原因,我正在使用Racket进行编码。

I was given a task in which I should create a function that, without filter, would receive a list as an input and return another list only with the even numbers of the first list. 我被赋予了一个任务,我应该在其中创建一个函数,在没有过滤器的情况下,将接收列表作为输入,并返回另一个列表,仅使用第一个列表的偶数。

I came up with this recursive definition of an iterative process: 我想出了迭代过程的这种递归定义:

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

It works fine. 它工作正常。 However, I get the result in a reverse order, eg: 但是,我以相反的顺序得到结果,例如:

(add-even '(1 2 3 4 5 6 7))
>> '(6 4 2)

What should I do to have the output in the same order of appearance on the input? 如何在输入上以相同的外观顺序输出?

I know how to do it with a reverse function. 我知道如何使用反向功能。 But that's not a very efficient way.. 但这不是一种非常有效的方式..

Of course you can do it without the iter procedure ... 当然你可以不用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)

But I assume you're using that to keep your add-even procedure tail-recursive. 但我假设你正在使用它来保持你的add-even过程的尾递归。 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. 你的accu可以是一个程序 (而不是一个列表),它填补了你的cons链中的“漏洞”。 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. 您可以填写最后一个值,而不是在计算结束时返回accu ,在这种情况下,该值为empty并使用identity初始化。

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 如果你使用了一个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 ...它清理,如果我们用 composecurry

(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: 在Racket中,内置for/list with #:when子句也可用于创建一个短函数:

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

(onlyeven '(1 2 3 4 5 6 7))
; => '(2 4 6)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM