Recursive state-Monade für die Akkumulation von Wert, während den Aufbau einer Liste?
Ich bin vollkommen neu in Haskell also entschuldigt, wenn die Frage ist dumm.
Was ich will zu tun ist, rekursiv eine Liste aufbauen, während gleichzeitig Aufbau eines akkumulierten Wertes basiert auf der rekursiven Aufrufe. Dies ist für ein problem, ich mache für einen Coursera-Kurs, damit ich nicht nach den genauen problem, aber etwas analoges.
Sagen Sie zum Beispiel, wollte ich eine Liste von ints und Doppel jeweils (ohne Berücksichtigung der für die Zwecke des Beispiels, dass ich konnte einfach map
), aber ich auch wollte zählen, wie viele Male die Zahl '5' in der Liste erscheint.
Damit zu tun, die Verdoppelung könnte ich dies tun:
foo [] = []
foo (x:xs) = x * 2 : foo xs
So weit, So einfach. Aber wie kann ich auch pflegen Sie eine zu zählen, wie viele Male x
ist eine fünf? Die beste Lösung, die ich habe, ist die Verwendung eines expliziten Akkumulators wie diese, die ich nicht mag, wie es kehrt die Liste, also müssen Sie tun, ein reverse-am Ende:
foo total acc [] = (total, reverse acc)
foo total acc (x:xs) = foo (if x == 5 then total + 1 else total) (x*2 : acc) xs
Aber ich fühle mich wie dieser sollte in der Lage sein, um behandelt werden schöner durch die State
Monade, die ich nicht verwendet haben, bevor, aber wenn ich versuche, eine Funktion zu konstruieren, passen die Muster, die ich gesehen habe, bekomme ich stecken bleiben, weil der rekursiven Aufruf foo
. Gibt es eine schönere Art, dies zu tun?
EDIT: muss ich diese Arbeit für sehr lange Listen, so dass jede rekursive Aufrufe werden müssen tail-recursive zu. (Das Beispiel habe ich hier verwaltet werden tail-rekursive Dank Haskell 's" tail recursion modulo cons').
- Verwandte Frage: "Tail-Optimierung - Garantie- loop-Codierung in Haskell".
- In welchem Sinne ist dein Beispiel tail-rekursiv? Ich glaube, dass es sich thunks und bewirkt, dass ein "memory leak". Selbst ein einfacher Aufruf
reverse
genug zu sein scheint, um einen Speicherverlust verursachen. - Wenn ich sage, es ist tail-rekursive, ich meinte die einfache Karte Beispiel, nicht die zweite code-fragment. TBH ich habe eine harte Zeit, herauszufinden, was ist und was nicht effizienten code in Haskell - es scheint zu funktionieren völlig anders als jede andere Sprache, die ich verwendet habe! Glaube, ich brauche zu tun, etwas mehr darüber zu Lesen 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dies ist eine einfache Falte
oder ausgedrückt mit
foldr
Den kumulierten Wert ist, ist ein paar der beiden Operationen.
Hinweise:
Können Sie
State
für die gleiche Sache, als auch, durch das betrachten jedes element als eine stateful-Berechnung. Das ist ein bisschen übertrieben, aber durchaus möglich. In der Tat, jede Falte kann ausgedrückt werden als eine Sequenz vonState
Berechnungen:Funktion
mapM_
ersten Karten jedes element vonxs
zu einer stateful-Berechnung durchmodify . f :: b -> State a ()
. Dann verbindet es eine Liste solcher Berechnungen in einer ArtState a ()
(er verwirft die Ergebnisse der monadischen Berechnungen, nur hält die Wirkung). Schließlich führen wir diese stateful Berechnung aufz
.map
, es wird die Rückseite der Liste. (Dies kann nützlich sein, manchmal, wenn Sie kümmern sich nicht um die Reihenfolge.)Mit
State
Monade es kann auch etwas sein wie: