Deklarative Programmierung

Werbung
Was bisher geschah
I
Pattern matching
I
algebraische Datentypen
I
rekursive Datentypen
(Peano-Zahlen, Listen, Binärbäume)
I
rekursive Funktionen
I
strukturelle Induktion
I
Rekursionsschemata
I
Funktionen höherer Ordnung
70
Auswertungsreihenfolge
inc :: Int -> Int
inc n = n + 1
2 Möglichkeiten, den Wert von inc(3 * 5) zu berechnen
Es wird bei beiden Möglichkeiten derselbe Wert berechnet.
(Haskell ist nebenwirkungsfrei.)
sq :: Int -> Int
sq x = x * x
sq (3 + 1)
71
Redex
Reduktion Termersetzung durch Funktionsanwendung
Redex reduzierbarer Teilterm
Redexe von mult ( 1 + 2 ) ( 2 + 3 )
mult :: Int -> Int -> Int
mult = \x y -> x * y
mult ( 1 + 2 )( 2 + 3 )
fst :: (a, b) -> a
fst ( x, _ ) = x
fst ( 1 + 2, 3 + 5 )
72
Auswertungs-Strategien
innermost Reduktion von Redexen, die keinen Redex
enthalten
(Parameterübergabe by value)
outermost Reduktion von Redexen, die in keinem Redex
enthalten sind
(Parameterübergabe by name)
(jeweils so weit links wie möglich zuerst)
mult :: Int -> Int -> Int
mult x = \y -> x * y
mult ( 1 + 2 )( 2 + 3 )
Teilterme in λ-Ausdrücken werden nicht reduziert.
(\ x -> 1 + 2) 1
73
Termination
inf :: Int
inf = 1 + inf
Auswertung von
fst (3, inf)
terminiert unter outermost-Strategie,
aber nicht unter innermost-Strategie
Fakt
Für jeden Ausdruck, für den die Auswertung unter irgendeiner
Strategie terminiert, terminert auch die Auswertung unter
outermost-Strategie.
74
Sharing von Teilausdrücken
jeder Funktionsaufruf ist lazy:
I
kehrt sofort zurück
I
Resultat ist thunk
I
thunk wird erst bei Bedarf ausgewertet
I
Bedarf entsteht durch Pattern Matching
sq :: Int -> Int
sq x = x * x
sq (3 + 1)
data N = Z | S N
nichtnull :: N -> Bool
nichtnull n = case n of
Z -> False ; S _ -> True
x = S undefined
nichtnull x
Lazy Evaluation (Bedarfsauswertung) =
Outermost-Reduktionsstrategie mit Sharing
75
Lazyness
jeder Wert wird erst bei Bedarf ausgewertet.
Listen sind Streams, der Tail wird erst bei Bedarf ausgewertet.
Wann die Auswertung stattfindet, lässt sich nicht beobachten.
Die Auswertung hat keine Nebenwirkungen.
unendliche Datenstruktur:
naturals :: [ Integer ]
naturals = from 0 where
from x = x : from ( x + 1 )
Liste aller Quadratzahlen? Primzahlen?
76
Unendliche Datenstrukturen
inf :: Int
inf = 1 + inf
fst(0, inf)
einsen :: [Int]
einsen = 1 : einsen
head einsen
take 3 einsen
nats :: [Int]
nats = 0 : map (+1) nats
takeWhile (<= 5) nats
77
Motivation: Datenströme
Folge von Daten:
I
I
I
erzeugen (producer)
transformieren
verarbeiten (consumer)
aus softwaretechnischen Gründen:
diese drei Aspekte im Programmtext trennen,
aus Effizienzgründen:
in der Ausführung verschränken
(bedarfsgesteuerte Transformation/Erzeugung)
78
Rekursive Stream-Definitionen
nats = 0 : map (+1) nats
fibonacci = 0
: 1
: zipWith (+) fibonacci ( tail fibonacci )
take 10 fibonacci
take 1 $ dropWhile (< 200) fibonacci
Welchen Wert hat bin ?
bin = False
: True
: concat ( map ( \ x -> [ x, not x ] )
( tail bin ) )
79
Primzahlen
Sieb des Eratosthenes
alle_ab :: Int -> [ Int ]
alle_ab n = n : alle_ab ( n+1 )
primzahlen :: [ Int ]
primzahlen = sieb $ alle_ab 2
sieb :: [ Int ] -> [ Int ]
sieb (x : xs) = x : ...
take 100 primzahlen
takeWhile (< 100) primzahlen
80
Strictness
Berechnung eines Funktions-Argumentes vor Anwendung der
Funktion
mitunter auch in Haskell sinnvoll
(z.B. Zeit- und Platzbeschränkung der Berechnung)
Syntax: f $! x berechnet denselben Wert wie f x, aber in
anderer Auswertungsreihenfolge:
f $! x wird erst dann ein Redex (und reduziert zu f x),
sobald nach (lazy) Auswertung x kein undefinierter Wert mehr
ist.
Beispiel: sq $! (1 + (sq 2) )
für Funktionen mit mehreren Argumenten:
Striktheit in jedem Argument einzeln.
81
Strikte Auswertung
Bei bekannter Striktheit kann der Compiler mitunter
effizienteren Code erzeugen (frühe Argumentauswertung)
z.B. Listen-Summe mit Akkumulator:
sum_n :: Integer -> [Integer] -> Integer
sum_n n [] = n
sum_n n ( x : xs ) = sum_n (n + x) xs
sum_n 0 [ 1,2,3]
sum_n 0 [ 1 .. 100000]
strikte Auswertung eines Teiltermes erzwingen:
sum_n n ( x : xs ) = (sum_n $!(n + x)) xs
strikte Version von foldl
sfoldl :: (a -> b -> a) -> a -> [b] -> a
sfoldl f x [] = x
sfoldl f x (y : ys) = ((sfoldl f) $! (f x y)) ys
82
Herunterladen