Jestem nowicjuszem w Schemacie (poprzez Rakietę) i (w mniejszym stopniu) programowaniu funkcjonalnym, i mogę skorzystać z porady dotyczącej plusów i minusów kumulacji poprzez zmienne a rekursja. Na potrzeby tego przykładu próbuję obliczyć średnią ruchomą. Tak więc, dla listy '(1 2 3 4 5)
, średnia z 3 okresów ruchomych wynosiłaby '(1 2 2 3 4)
. Chodzi o to, że żadne liczby przed okresem nie są jeszcze częścią obliczeń, a kiedy osiągniemy długość okresu w zbiorze, zaczniemy uśredniać podzbiór listy według wybranego okresu.Schemat/Rakieta Najlepsze praktyki - Rekursja vs Zmienna akumulacja
Więc moja pierwsza próba wyglądała mniej więcej tak:
(define (avg lst)
(cond
[(null? lst) '()]
[(/ (apply + lst) (length lst))]))
(define (make-averager period)
(let ([prev '()])
(lambda (i)
(set! prev (cons i prev))
(cond
[(< (length prev) period) i]
[else (avg (take prev period))]))))
(map (make-averager 3) '(1 2 3 4 5))
> '(1 2 2 3 4)
To działa. Podoba mi się użycie mapy. Wydaje się, że jest kompozycyjny i otwarty na refaktoryzację. Widziałam w przyszłości o kuzynów, takich jak:
(map (make-bollinger 5) '(1 2 3 4 5))
(map (make-std-deviation 2) '(1 2 3 4 5))
itp
Ale to nie w duchu Scheme (prawda?), bo jestem z akumulacją efektów ubocznych. Więc przepisałem go tak, aby wyglądał tak:
(define (moving-average l period)
(let loop ([l l] [acc '()])
(if (null? l)
l
(let* ([acc (cons (car l) acc)]
[next
(cond
[(< (length acc) period) (car acc)]
[else (avg (take acc period))])])
(cons next (loop (cdr l) acc))))))
(moving-average '(1 2 3 4 5) 3)
> '(1 2 2 3 4)
Teraz ta wersja jest trudniejsza do zignorowania na pierwszy rzut oka. Więc mam kilka pytań:
Czy jest bardziej eleganckim sposobem wyrażenia rekurencyjną wersję korzystaniu z niektórych zbudowany w konstrukcji iteracji rakietę (jak
for/fold
)? Czy to jest rekursywne, nawet jak napisane?Czy istnieje sposób na napisanie pierwszej wersji bez użycia zmiennej akumulatora?
Czy ten typ problemu jest częścią większego wzorca, dla którego akceptowane są najlepsze praktyki, szczególnie w Planie?
Cóż, to po prostu lepsze. :) Wielkie dzięki. – Scott