Die Reduktionsreihenfolge sei durch eine spezielle Funktion,
strict, beeinflussbar. Ein Term der Form
strict f e wird
reduziert, indem zuerst
e zur Kopf-Normal-Form reduziert wird und dann
f auf
e
angewendet wird. Ein Ausdruck
e ist in Kopf-Normal-Form, wenn
e eine
Funktion ist oder
e ein Datentypkonstruktor ist, angewandt auf keine oder mehrere Argumente (mehr Information zur
Kopf-Normal-Form (head normal form)). Ein Ausdruck in Normalform
ist auch in Kopf-Normal-Form, aber nicht umgekehrt. Z.B.:
e1 : e2 ist in Kopf-Normal, aber nur in Normalform, wenn sowohl
e1
als auch
e2 in Normalform sind.
In dem Ausdruck
strict f e wird
e, solange keine weiteren Aufrufe von
strict vorliegen, selbst outermost reduziert (im Haskell
Standard-Verfahren). Currying beeinflusst
strict genauso, wie jede andere Funktion auch. Bei
strict (f e1) e2 e3 wirkt
strict
auf
e2 nicht auf
e1 oder
e3. Die Arbeitsweise von
strict kann auch auf
diese Weise ausgedrückt werden:
strict f x = if x = ⊥ then ⊥ else x
.
Kehren wir zu unserem Ursprungsproblem
sum zurück. Zuerst muss eine neue Definition der
foldl Funktion gefunden werden,
die unsere Addition in
sum strikt auswerten lässt.
01 -- allgemeine Definition einer strikten foldl Funktion
02 sfoldl (⊗) α = α
03 sfoldl (⊗) α (x:xs) = strict (sfoldl (⊗)) (α (⊗) x) xs
|
Das Dualitätstheorem zu fold besagt: Wenn ein Operator (⊗) assoziativ ist und e die Identität dieser Operation repräsentiert, gilt:
foldr (⊗) e xs = foldl (⊗) e xs
Dennoch darf nicht vernachlässigt werden, dass die unterschiedlichen Operationen ⊗ unterschiedliche Zeit- und Raumkomplexitäten aufweisen
können. Angenommen, ⊗ ist strikt in der Auswertung beider Argumente und kann in konstanter Zeit O(1) berechnet werden. Beispiele sind
(+) oder (x), dann beträgt die Laufzeit- und Speicherplatzkomplexität jeweils O(n) bei der Bearbeitung von Listen der Länge n. Wenn die fold-Funktion
korrekt gegen eine sfoldf ersetzt werden kann (für (+), (x) ist dies der Fall) bleibt die Laufzeit bei O(n), die Speichplatzkomplexität
sinkt allerdings auf O(1). Eine strikte fold Funktion ist in solchen Fällen also sinnvoller. Falls ⊗ nicht diese Bedingungen erfüllt ist eine
Entscheidung nicht einfach. Generell gilt die Daumenregel, wenn ⊗ nicht strikt in beiden Argumenten ist, ist foldr häufig die effizientere Methode.
Beispiele für solche Operationen sind die ++-Operation und die and-Funktion (mit and = foldr (∧) True).