Sono nuovo a Scheme (via Racket) e (in misura minore) programmazione funzionale, e potrei usare qualche consiglio sui pro e contro dell'accumulo tramite variabili vs ricorsione. Ai fini di questo esempio, sto cercando di calcolare una media mobile. Pertanto, per un elenco '(1 2 3 4 5)
, la media mobile a 3 periodi sarebbe '(1 2 2 3 4)
. L'idea è che qualsiasi numero prima del periodo non faccia ancora parte del calcolo, e una volta raggiunta la lunghezza del periodo nell'insieme, iniziamo a calcolare la media del sottoinsieme dell'elenco in base al periodo scelto.Schema/racchetta Best Practice - Ricorsione contro accumulo variabile
Quindi, il mio primo tentativo sembrava qualcosa di simile:
(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)
Questo funziona. E mi piace l'uso della mappa. Sembra compositivo e aperto al refactoring. Ho potuto vedere in futuro con i cugini come:
(map (make-bollinger 5) '(1 2 3 4 5))
(map (make-std-deviation 2) '(1 2 3 4 5))
ecc
Ma, non è nello spirito di Scheme (giusto?) Perché sto accumulando con effetti collaterali. Così ho riscritto per assomigliare a questo:
(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)
Ora, questa versione è più difficile da Grok a prima vista. Così ho un paio di domande:
C'è un modo più elegante per esprimere la versione ricorsiva utilizzando alcuni del costruito in costrutti di iterazione di racket (come
for/fold
)? È anche coda ricorsiva come scritto?C'è un modo per scrivere la prima versione senza l'uso di una variabile di accumulatore?
Questo tipo di problema fa parte di un modello più ampio per il quale esistono best practice accettate, in particolare in Scheme?
Bene, questo è solo il modo migliore. :) Molte grazie. – Scott