10
votes

Schéma / Raquette Meilleure pratique - Récursion vs accumulation variable

Je suis nouveau dans le schéma (via une raquette) et (dans une moindre mesure) la programmation fonctionnelle et pourrait utiliser certains conseils sur les avantages et les inconvénients de l'accumulation via des variables vs récursives. Aux fins de cet exemple, j'essaie de calculer une moyenne mobile. Donc, pour une liste '(1 2 3 4 5) , la moyenne mobile de 3 périodes serait ' (1 2 2 3 4) . L'idée est que tous les chiffres avant la période ne font pas encore partie du calcul, et une fois que nous atteignons la longueur de la période de l'ensemble, nous commençons à la moyenne du sous-ensemble de la liste en fonction de la période choisie.

Donc, ma première tentative a regardé Quelque chose comme ça: xxx

cela fonctionne. Et j'aime l'utilisation de la carte. Il semble composé et ouvert au refactoring. Je pouvais voir dans l'avenir avoir des cousins ​​comme: xxx

etc.

mais, ce n'est pas dans l'esprit de schéma (non?) Parce que je suis " m accumuler avec des effets secondaires. Je l'ai donc réécrit pour ressembler à ceci: xxx

maintenant, cette version est plus difficile à grok à première vue. Donc, j'ai quelques questions:

  1. Y a-t-il un moyen plus élégant d'exprimer la version récursive en utilisant certaines des constructions d'itération intégrées de raquette (comme pour / pli )? Est-ce même la queue récursive comme écrite?

  2. existe-t-il un moyen d'écrire la première version sans utiliser une variable d'accumulateur?

  3. est ce type de problème d'un modèle plus important pour lequel il est accepté les meilleures pratiques, en particulier dans le schéma?


0 commentaires

3 Réponses :


7
votes

C'est un peu étrange pour moi que vous commencez avant la première de la liste, mais vous arrêtez fortement à la fin de celui-ci. C'est-à-dire que vous prenez le premier élément par lui-même et les deux premiers éléments, mais vous ne faites pas la même chose pour le dernier élément ou les deux derniers éléments.

C'est un peu orthogonal à la solution pour le problème . Je ne pense pas que l'accumulateur vous facilite votre vie, et j'écrirais la solution sans cela: P>

Raquette #Lang P>

(require rackunit)

;; given a list of numbers and a period, 
;; return a list of the averages of all 
;; consecutive sequences of 'period' 
;; numbers taken from the list.
(define ((moving-average period) l)
  (cond [(< (length l) period) empty]
        [else (cons (mean (take l period)) 
                    ((moving-average period) (rest l)))]))

;; compute the mean of a list of numbers
(define (mean l)
  (/ (apply + l) (length l)))

(check-equal? (mean '(4 4 1)) 3)
(check-equal? ((moving-average 3) '(1 3 2 7 6)) '(2 4 5))


1 commentaires

Eh bien, c'est juste mieux. :) Merci beaucoup.



0
votes

Eh bien, en règle générale, vous souhaitez séparer la manière dont vous recueillez et / ou itérale du contenu des étapes d'itération. Vous mentionnez pli dans votre question, et ce point à droite: vous voulez une forme de fonction supérieure de commande qui gérera la mécanique de la trafuration de la liste et appelle une fonction que vous fournissez avec les valeurs du fenêtre.

J'ai préparé cela en trois minutes; Il est probablement faux de bien de nombreuses manières, mais cela devrait vous donner une idée: xxx


0 commentaires

0
votes

Alternativement, vous pouvez définir une fonction qui convertit une liste dans des fenêtres N-Element puis cartographiez la moyenne sur les fenêtres.

(define (partition lst default size)
  (define (iter lst len)
    (if (< len 3)
      empty
      (cons (take lst 3)
            (iter (rest lst)
                  (- len 1)))))
  (iter (cons default (cons default lst))
        (+ (length lst) 2)))


0 commentaires