Universität Bielefeld Programmieren in Haskell Sauthoff Programmieren in Haskell Rechenstrategien Strategien WS 2011/2012 Georg Sauthoff1 Universität Bielefeld AG Praktische Informatik November 15, 2011 1 [email protected] Wiederholung length Universität Bielefeld Programmieren in Haskell Sauthoff 1 2 3 Die Funktion length hatten wir wie folgt definiert: length :: [ a ] -> Int length [] = 0 length ( x : xs ) = 1 + length xs Aber was ist von folgender Definition zu halten? 4 length xs ++ ys == length xs + length ys reicht das? Rechenstrategien Wiederholung length Strategien Grundbegriffe zu Auswertungs-Strategien: Universität Bielefeld Programmieren in Haskell Sauthoff Rechnen = Anwenden von Gleichungen in Formeln Redex = Stelle in einer Formel, an der die linke Seite einer Gleichung “passt” (Reducible Expression) “passt” = die auf der linken Seite verlangten Konstruktoren der Argumente liegen vor Rechenstrategien Strategien Normalform Ein Ausdruck ist in Normalform wenn er keinen Redex enthält. Beispiel 1 head ( x : xs ) = x Universität Bielefeld Programmieren in Haskell Sauthoff 2 3 4 5 6 -- ist anwendbar auf die Formel und ergibt head (1:2:2:[]) => 1 head (1:([3 ,4]++[5 ,6])) => 1 head (1: ones ) where ones = 1: ones => 1 ist (noch) nicht anwendbar auf 7 8 9 10 head ([1 ,3 ,4] ++ [5 ,6]) head ( map (1+) [1 ,2 ,3]) head ones where ones = 1: ones Es muss erst eine Gleichung für ++, map oder ones angewandt werden. Rechenstrategien Strategien Lage von Redexen in einer Formel Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Strategien Ein Redex ist innermost, wenn er keinen weiteren Redex enthält, outermost, wenn er in keinem weiteren Redex enthalten ist, “zwischendrin”, sonst. Beispiel Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Strategien Auswertungs-Strategien Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien leftmost innermost: immer den Redex wählen, der am weitesten links steht und innermost ist. leftmost outermost: immer den Redex wählen, der am weitesten links steht und outermost ist. gemischt: man kann sich viele weitere Strategien vorstellen . . . Strategien if-then-else Universität Bielefeld Besonderheit von if_then_else: Programmieren in Haskell Sauthoff Seine definierenden Gleichungen sind Rechenstrategien Strategien if True then x else y = x (1) if False then x else y = y (2) Ein Redex wird in jedem Fall leftmost outermost berechnet. Je nach Ergebnis für C wird A oder B nicht berechnet. Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Diese Regel für if_then_else gilt in allen Programmiersprachen. Ohne sie könnte man keine terminierende Rekursion programmieren: f ( x ) = if x <= 0 then else 2 + f (x -1) Innermost-Strategie führt zu endloser Berechnung des else-Falles. Strategien Eigenschaften der Strategien Universität Bielefeld Programmieren in Haskell 1 Ob eine Rechnung terminiert, hängt i.A. von der Strategie ab. 2 Wenn zwei verschiedene Strategien, angewandt auf die gleiche Formel, terminieren, liefern sie das gleiche Ergebnis. 3 Im Fall (2) kann sich der Rechenaufwand stark unterscheiden. 4 Wenn für eine Formel F irgendeine Strategie terminiert, dann terminiert für F auch “leftmost outermost”. 5 “leftmost innermost” terminiert seltener als “leftmost outermost”. Sauthoff Rechenstrategien Strategien Anschauliche Bedeutung Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien innermost: Alle Argumente einer Funktion werden ganz ausgerechnet, bevor die Funktion “aufgerufen” wird. outermost: Die Argumente einer Funktion werden immer nur so weit ausgerechnet, wie es die Funktion für ihren nächsten Schritt braucht. Strategien Lazy Evaluation Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Strategien Haskell verwendet lazy evaluation (verzögerte Auswertung), das ist leftmost outermost + graph reduction graph reduction ist eine Zusatzregel, die die Duplikation unausgerechneter Formeln vermeidet. Beispiel zur graph reduction Universität Bielefeld Programmieren in Haskell Sauthoff 1 twice x = x * x twice (3 + 4) ↑ ↑ outermost innermost würde blindlings outermost reduziert zu (3 + 4) ∗ (3 + 4) wo nun der Ausdruck (3 + 4) zweimal berechnet werden müsste. Rechenstrategien Strategien Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Strategien 1 2 Stattdessen wird reduziert twice (3+4) = x * x where x = 3+4 worin durch die “Nebenrechnung” 3 + 4 nur einmal berechnet wird. Einfluss von Lazy Evaluation auf die Auswertung Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Strategien Unter lazy evaluation kann es sein, dass eine Funktion in einem bestimmten Kontext nur einen Teil ihres Ergebnisses berechnet. Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Hier die naheliegende Implementierung von minimum: 1 2 3 4 minimum ( a : as ) = min a as where min a [] = a min a ( b : x ) = if a <= b then min a x else min b x Strategien Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Hier eine alternative Implementierung, die bequemerweise den Insertion-Sort benutzt minimum ( a : as ) = head ( isort ( a : as )) Sehen wir genauer hin! Strategien Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Strategien 1 2 3 4 5 Die Definition von isort war: isort [] = [] isort ( a : as ) = insert a ( isort as ) insert a [] = [ a ] insert a ( b : as ) = if a <= b then a : b : as else b :( insert a as ) Universität Bielefeld Lazy Evaluation berechnet in einer Formel immer an der “äußersten” Stelle, an der eine Gleichung anwendbar ist: Programmieren in Haskell Zunächst kann immer nur die Gleichung isort.2 angewandt werden, am Ende einmal isort.1 Rechenstrategien head head isort insert : => a1 Sauthoff insert : a1 a2 a2 insert : an an [] [] Strategien Universität Bielefeld Danach wird n-mal insert angewandt, beginnend bei an . Nehmen wir an, a5 ist das kleinste Element. Streng “outermost” entsteht nun Programmieren in Haskell Sauthoff Rechenstrategien head Strategien : => a5 insert a1 insert a2 insert a n−1 innerhalb des Kastens könnte man weiterrechnen, aber das wäre nicht “outermost”. [a n] Universität Bielefeld Programmieren in Haskell head braucht nicht mehr als den obersten Konstruktur (:), um sein Ergebnis zu liefern Sauthoff Rechenstrategien Strategien head => a5 : a5 Es werden ∼ 2 · n Gleichungen angewandt. Der Rest der Operationen steckt im Kasten und wird nicht benötigt! Fazit Universität Bielefeld Programmieren in Haskell Sauthoff Rechenstrategien Strategien Durch Lazy Evaluation müssen weniger Reduktionen durchgeführt werden.