2016-10-17 1 views
1

Я кодирую ракетку по образовательным причинам.Как заказать мою переменную накапливания в этом случае на 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) 

Что я должен сделать, чтобы иметь выход в том же порядке появления на входе?

Я знаю, как это сделать с обратной функцией. Но это не очень эффективный способ ..

ответ

3

Конечно, вы можете сделать это без 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)

Итак, теперь вы получите хвост рекурсию и вы строите список в прямом порядке. Я призываю вас пройти эту оценку, чтобы увидеть, как это работает. Это continuation passing style.


И, возможно, процедура будет лучше, если вы переименовали VARS немного

(define (add-even lista) 
    (define (iter lk) 
    (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)

... И это cle анс вверх даже более если бы мы использовали 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)
0

В Ракетка, встроенный в for/list с #:when пунктом также может быть использован для создания короткого функции:

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

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

Не был бы 'фильтр 'будет немного более прямо здесь? – naomik

+0

OP специально хочет создать функцию без фильтра (см. Первое предложение второго параграфа вопроса). – rnso

Смежные вопросы