Der komplizierte Teil ist die Schleife. Beginnen wir damit. Eine Schleife wird normalerweise in einen funktionalen Stil umgewandelt, indem die Iteration mit einer einzelnen Funktion ausgedrückt wird. Eine Iteration ist eine Transformation der Schleifenvariablen.
Hier ist eine funktionale Implementierung einer allgemeinen Schleife:
loop : v -> (v -> v) -> (v -> Bool) -> v
loop init iter cond_to_cont =
if cond_to_cont init
then loop (iter init) iter cond
else init
Es dauert (ein Anfangswert der Schleifenvariablen, die Funktion, die eine einzelne Iteration [in der Schleifenvariablen] ausdrückt) (eine Bedingung, um die Schleife fortzusetzen).
In Ihrem Beispiel wird eine Schleife in einem Array verwendet, die ebenfalls unterbrochen wird. Diese Fähigkeit in Ihrer imperativen Sprache ist in die Sprache selbst eingebettet. In der funktionalen Programmierung wird eine solche Fähigkeit normalerweise auf Bibliotheksebene implementiert. Hier ist eine mögliche Implementierung
module Array (foldlc) where
foldlc : v -> (v -> e -> v) -> (v -> Bool) -> Array e -> v
foldlc init iter cond_to_cont arr =
loop
(init, 0)
(λ (val, next_pos) -> (iter val (at next_pos arr), next_pos + 1))
(λ (val, next_pos) -> and (cond_to_cont val) (next_pos < size arr))
Drin :
Ich benutze ein ((val, next_pos)) Paar, das die außerhalb sichtbare Schleifenvariable und die Position im Array enthält, die diese Funktion verbirgt.
Die Iterationsfunktion ist etwas komplexer als in der allgemeinen Schleife. Mit dieser Version kann das aktuelle Element des Arrays verwendet werden. [Es ist in Curryform .]
Solche Funktionen werden üblicherweise "fold" genannt.
Ich setze ein "l" in den Namen, um anzuzeigen, dass die Akkumulation der Elemente des Arrays linksassoziativ erfolgt. die Gewohnheit imperativer Programmiersprachen nachzuahmen, ein Array vom niedrigen zum hohen Index zu durchlaufen.
Ich habe ein "c" in den Namen eingefügt, um anzuzeigen, dass diese Fold-Version eine Bedingung annimmt, die steuert, ob und wann die Schleife vorzeitig gestoppt werden soll.
Natürlich sind solche Hilfsprogrammfunktionen wahrscheinlich in der Basisbibliothek verfügbar, die mit der verwendeten funktionalen Programmiersprache geliefert wird. Ich habe sie hier zur Demonstration geschrieben.
Nachdem wir alle Tools haben, die im Imperativfall in der Sprache verfügbar sind, können wir uns an die Implementierung der spezifischen Funktionalität Ihres Beispiels wenden.
Die Variable in Ihrer Schleife ist ein Paar ('answer', ein Boolescher Wert, der codiert, ob fortgefahren werden soll).
iter : (Int, Bool) -> Int -> (Int, Bool)
iter (answer, cont) collection_element =
let new_answer = answer + collection_element
in case new_answer of
10 -> (new_answer, false)
150 -> (new_answer + 100, true)
_ -> (new_answer, true)
Beachten Sie, dass ich eine neue "Variable" "new_answer" verwendet habe. Dies liegt daran, dass ich in der funktionalen Programmierung den Wert einer bereits initialisierten "Variablen" nicht ändern kann. Ich mache mir keine Sorgen um die Leistung, der Compiler kann den Speicher von 'answer' für 'new_answer' über die Lebenszeitanalyse wiederverwenden, wenn er dies für effizienter hält.
Dies in unsere zuvor entwickelte Schleifenfunktion zu integrieren:
doSomeCalc :: Array Int -> Int
doSomeCalc arr = fst (Array.foldlc (0, true) iter snd arr)
"Array" ist hier der Name des Moduls, dessen Exportfunktion foldlc lautet.
"Faust", "Sekunde" stehen für Funktionen, die die erste, zweite Komponente ihres Paarparameters zurückgeben
fst : (x, y) -> x
snd : (x, y) -> y
In diesem Fall erhöht der "punktfreie" Stil die Lesbarkeit der Implementierung von doSomeCalc:
doSomeCalc = Array.foldlc (0, true) iter snd >>> fst
(>>>) ist Funktionszusammensetzung: (>>>) : (a -> b) -> (b -> c) -> (a -> c)
Es ist dasselbe wie oben, nur der Parameter "arr" wird auf beiden Seiten der Definitionsgleichung weggelassen.
Eine letzte Sache: Prüfung auf Groß- und Kleinschreibung (Array == Null). In besser gestalteten Programmiersprachen, aber auch in schlecht gestalteten Sprachen mit einigen grundlegenden Disziplinen verwendet man eher einen optionalen Typ , um Nichtexistenz auszudrücken. Das hat nicht viel mit funktionaler Programmierung zu tun, worum es letztendlich geht, also beschäftige ich mich nicht damit.
break
undreturn answer
durch einreturn
innerhalb der Schleife ersetzt werden kann. In FP könnten Sie diese vorzeitige Rückkehr mithilfe von Fortsetzungen implementieren, siehe z. B. en.wikipedia.org/wiki/Continuation