11.1.2011

Werbung
Was bisher geschah
I
Algebraische Datentypen
I
strukturelle Induktion
I
Rekursionsschemata
I
Funktionen höherer Ordnung (z.B. map, fold, filter
I
Monaden (Maybe, List, IO)
I
Parser-Monade (Parsec)
117
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)
118
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 )
119
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)
Teilterme in λ-Ausdrücken werden nicht reduziert.
mult :: Int -> Int -> Int
mult x = \y -> x * y
mult ( 1 + 2 )( 2 + 3 )
(\ x -> 1 + 2) 1
120
Lazy Evaluation in Haskell
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
I
Sharing von Teilausdrücken
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 (error "42")
nichtnull x
Lazy Evaluation (Bedarfsauswertung) =
Outermost-Reduktionsstrategie mit Sharing
121
Termination
inf :: Int
inf = 1 + inf
Auswertung von
fst (0, inf)
terminiert unter outermost-Strategie,
aber nicht unter innermost-Strategie
Fakt 1
Für jeden Ausdruck, für den die Auswertung unter irgendeiner
Strategie terminiert, terminert auch die Auswertung unter
outermost-Strategie.
122
Unendliche Datenstrukturen
einsen :: [Int]
einsen = 1 : einsen
head einsen
take
take
take
take
:: Int -> [a] -> [a]
0 _ = []
(n + 1) [] = ...
(n + 1) (x : xs) = ...
take 3 einsen
nats :: [Int]
nats = 0 : map (+1) nats
takeWhile (<= 5) nats
123
Motivation: Datenströme
Folge von Daten:
I
erzeugen (producer)
I
transformieren
I
verarbeiten (consumer)
aus softwaretechnischen Gründen diese drei Aspekte im
Programmtext trennen,
aus Effizienzgründen in der Ausführung verschränken
(bedarfsgesteuerter Transformation/Erzeugung)
124
Beispiele
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 ) )
125
Thue-Morse-Wort
t := limn→∞ τ n (0) für τ : 0 7→ 01, 1 7→ 10
t = 0110100110010110 . . .
t ist kubikfrei
Folge der Abstände zwischen den Nullen
v := 210201210120 . . .
ist auch Fixpunkt eines Morphismus
v ist quadratfrei
126
Beispiel Primzahlen
Sieb des Eratosthenes
primes :: [ Int ]
primes = sieve [2 ..]
sieve :: [ Int ] -> [ Int ]
sieve (x : xs) =
x : sieve [y | y <- xs, mod y x /= 0]
take 100 primes
takeWhile (< 100) primes
127
Strikte Auswertung
Symbol ⊥ für undefinierte Werte
zu jedem Typ T betrachte T⊥ = {⊥} ∪ T
Funktion f heißt strikt, wenn f (⊥) = ⊥.
(Funktionswert immer undefiniert, wenn ein Argumentwert
undefiniert ist.)
in Haskell:
I
Konstruktoren (Cons,. . . ) sind nicht strikt,
I
Destruktoren (head, tail,. . . ) sind strikt.
für Funktionen mit mehreren Argumenten:
betrachte Striktheit in jedem Argument einzeln.
Falls Striktheit bekannt ist, kann der Compiler effizienteren
Code erzeugen
(frühe Argumentauswertung)
128
Strikte Auswertung in Haskell
seq :: a -> b -> b
undefined ‘seq‘ y = undefined
x ‘seq‘ y
= y
($!) :: (a -> b) -> a -> b
f $! x = x ‘seq‘ f x
129
Beispiele
square x = x * x
square ( 1 + 2 )
square $! ( 1 + 2 )
Striktheit in einzelnen Argumenten
(f $! x) y
(f x) $! y
(f $! x) $! y
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 .. 100000000]
strikte Auswertung eines Teiltermes erzwingen:
sum_n n ( x : xs ) = (sum_n $!(n + x)) xs
130
Funktionale und logische Programmierung
I
funktionale Programmierung:
LISP (John McCarthy, 1957)
benutzerdefinierte Funktionen,
definiert durch Gleichungen (Ersetzungsregeln)
Rechnen = Normalform bestimmen
Methode: Termersetzung
I
logische Programmierung:
Prolog (Alain Colmerauer, 1972)
benutzerdefinierte Relationen (Prädikate),
definiert durch Schlussregeln (Implikationen).
Rechnen = Schlussfolgerung (Widerspruch) ableiten
Methode: prädikatenlogische Resolution
131
Wiederholung: Prolog-Syntax
Regel (Klausel) a :- a1, ..., an.
Bedeutung in Prädikatenlogik (der ersten Stufe)
(∀X1 · · · ∀Xn ((a1 ∧ · · · ∧ an ) → a)
wobei X1 , . . . Xn alle in a, a1 , . . . , an
vorkommenden Variablen sind.
Rumpf a1 ∧ . . . ∧ an , Kopf a
Fakt Atom a. (positives Literal, Regel ohne Rumpf)
Bedeutung in Prädikatenlogik (der ersten Stufe):
∀X1 · · · ∀Xn a, wobei X1 , . . . Xn alle in a
vorkommenden Variablen sind.
Zielklausel (Query, Anfrage) ?- a1, ..., an.
Bedeutung in Prädikatenlogik (der ersten Stufe):
(∀X1 · · · ∀Xn (a1 ∧ · · · ∧ an )
wobei X1 , . . . Xn alle in a1 , . . . , an vorkommenden
Variablen sind.
Variablennamen beginnen mit Großbuchstaben,
Funktions- und Relationssymbole mit Kleinbuchstaben
132
Wiederholung: Prolog-Programme
Programm P (Wissensbasis):
endliche Menge von Fakten und Regeln,
repräsentiert eine prädikatenlogische
Formelmenge Φ,
repräsentiert
eine prädikatenlogische Formel
V
ϕ = ψ∈Φ ψ
Beispiel: Programm P
liest(max,krimi).
liest(bob,zeitung).
liest(tina,arztroman).
mag(tina,X) :- liest(X,krimi).
repräsentiert die Formelmenge
Φ = {l(m, k ), l(b, z), l(t, a), ∀x(l(x, k ) → m(t, x))}
133
Wiederholung: Prolog-Anfragen
Zielklausel Atom
repräsentiert eine prädikatenlogische Formel ψ
Beispiel: ?- mag (tina,X).
repräsentiert die Formel ψ = mag(ina, X )
134
Wiederholung: Prolog-Auswertung
Ausgewertet werden Paare (Φ, ψ) aus
I
Programm Φ
I
Zielklausel ψ
(prädikatenlogische Darstellung von Programm und Anfrage)
Antwort: Substitution θ mit Φ |= θ(ψ)
(Prolog-Ausgabe: Grundinstanzen θ(ψ) der Zielklausel ψ)
135
Prolog: Bestimmung der Antworten
I
durch Lösung des Problemes
Für welche Substitutionen θ gilt Φ |= θ(ψ)?
I
durch Lösung des äquivalenten Problemes:
Für welche Substitutionen θ ist die Formelmenge
Φ ∪ ¬θ(ψ) unerfüllbar?
I
durch Lösung des äquivalenten Problemes:
Für welche Substitutionen θ gilt Φ ∪ ¬θ(ψ) |= f ?
I
durch Bestimmung der Substitutionen θ, für die f aus
Φ ∪ ¬θ(ψ) syntaktisch herleitbar ist.
I
durch prädikatenlogische Resolution (mit festgelegter
Auswertungsreihenfolge, SLD-Resolution)
136
Beispiel für Prolog-Auswertung
Programm P:
p(a,b).
p(b,c).
p(c,d).
e(X,Y) :- p(X,Y).
e(X,Y) :- p(X,Z), e(Z,Y).
Zielklausel e(X , d)
Prädikatenlogische Bedeutung:
I
Programm P:
p(a, b), p(b, c), p(c, d), ∀X ∀Y (p(X , Y ) → e(X , Y )),
Φ=
∀X ∀Y ∀Z (p(X , Z ) ∧ e(Z , Y ) → e(X , Y ))
I
Zielklausel ψ = e(X , d)
I
negierte Zielklausel ¬ψ = ¬e(X , d)
I
Problem


 ¬e(X , d), p(a, b), p(b, c), p(c, d),

∀X ∀Y (p(X , Y ) → e(X , Y )),
{¬ψ} ∪ Φ =


∀X ∀Y ∀Z (p(X , Z ) ∧ e(Z , Y ) → e(X , Y ))
137
Wiederholung Unifikation
Substitution: partielle Funktion θ : X → Term(Σ, X ), wobei
keine Variable x, für welche θ(x) definiert ist, für
ein y ∈ X in f (y ) vorkommt,
Notation: [x 7→ t1 , y 7→ t2 , . . .]
Unifikator der Terme (Atome, Literale) s und t:
Substitution θ mit sθ = tθ
mgu(s, t) allgemeinster Unifikator der Terme (Atome,
Literale) s und t:
Unifikator θ für s und t, so dass zu jedem
Unifikator σ für s und t eine Substitution ρ für s
und t existiert, so dass gilt:
σ(s) = ρ(θ(s))
138
Wiederholung Unifikationsalgorithmus
zur Bestimmung des mgu (sofern dieser existiert)
Eingabe: Terme (Atome, Literale) s, t
Ausgabe: (unifizierbar, mgu(s, t)), falls mgu(s, t) existiert,
sonst nicht unifizierbar
Algorithmus (rekursiv) : unifiziere(s, t)
BF1 falls s, t Konstanten:
falls s = t: (unifizierbar, mgu(s, t) = []),
sonst nicht unifizierbar
BF2 falls s Variable, t Konstante:
[s 7→ t] in θ einfügen und auf alle rechten Seiten in θ
anwenden
BF3 falls s Variable, t = f (t1 , . . . , tn ):
falls s nicht in t vorkommt: mgu(s, t) = [s 7→ t],
sonst nicht unifizierbar
RF falls s = g(s1 , . . . , sm ), t = f (t1 , . . . , tn ):
falls m 6= n oder f 6= g: nicht unifizierbar
sonst θ = unifiziere(s1 , t1 ), . . . , unifiziere(sn , tn )
139
Beispiel für Prolog-Auswertung
Programm:
append(nil,Y,Y).
append(cons(X,Y),Z,cons(X,W)) :append(Y,Z,W).
Anfragen
????-
append
append
append
append
(cons(a,nil),cons(b,nil),Z).
(X,Y,nil).
(X,Y,cons(a,nil)).
(X,X,cons(a,cons(a,nil))).
140
Prolog-Interpreter in Haskell
I
Datentypen für
I
I
I
I
I
I
I
I
I
Funktions- und Prädikatsymbole Identifier (String)
Variablen Identifier (String)
Terme Tree
Atome (Identifier, [Tree])
Regeln (Atom, [Atom])
Fakten (Atom, [])
Anfragen (Regeln mit leerem Kopf)
Programme [Regel]
Substitutionen Map s Term
141
Suche in Haskell
Modellierung von Suche/Nichtdeterminismus in Haskell: Liste
von Resultaten, vgl.
permutationen :: [a] -> [[a]]
permutationen [] = return []
permutationen (x:xs) = do
ys <- perms xs
(pre, post) <zip (inits xs) (tails xs)
return $ pre ++ x : post
Phil Wadler: How to replace failure by a list of successes—a
method for exception handling, backtracking, and pattern
matching in lazy functional languages. 1985.
http://homepages.inf.ed.ac.uk/wadler/
142
Prolog-Interpreter
query :: [Clause] -> [Atom] -> [Substitution]
query cs [] = return M.empty
query cs (a : as) = do
u1 <- single cs a
u2 <- query cs $ map ( apply u1 ) as
return $ u1 ‘times‘ u2
single :: [Clause] -> Atom -> [Substitution]
single cs a = do
c <- cs
let c’ = rename c -- VORSICHT
u1 <- maybeToList $ unify a $ head c’
u2 <- query cs $ map ( apply u1 ) $ body c’
return $ u1 ‘times‘ u2
143
Global eindeutige Namen
bei jeder Benutzung jeder Klausel müssen deren Variablen
umbenannt werden (= durch „frische“ Namen ersetzt).
Globalen Zähler hinzufügen =
Zustands-Monaden-Transformator anwenden.
single :: [Clause] -> Atom -> [Substitution]
single cs a = do
c <- cs
import Control.Monad.State
single :: [Clause] -> Atom
-> StateT Int [] Substitution
single cs a = do
c <- lift cs
144
Ideales und Reales Prolog
wie hier definiert (ideal):
I
Semantik ist deklarativ
I
Reihenfolge der Regeln im Programm und Atome in
Regel-Rumpf beeinflusst Effizienz, aber nicht Korrektheit
reales Prolog:
I cut (!) zum Abschneiden der Suche
I
I
green cut: beeinflusst Effizienz
red cut: ändert Semantik
merke: cut ≈ goto, grün/ rot schwer zu unterscheiden
I
Regeln mit Nebenwirkungen (u. a. für Ein/Ausgabe)
für beides: keine einfache denotationale Semantik
145
Erweiterungen
I
eingebaute Operationen (Maschinenzahlen)
I
effiziente Kompilation (für Warren Abstract Machine)
I
Modi: Deklaration von In/Out und Determinismus (Mercury)
I
Funktionen/Prädikate höherer Ordnung:
Lambda-Prolog (Dale Miller) http:
//www.lix.polytechnique.fr/~dale/lProlog/
I
statisches Typsystem: Mercury (Fergus Henderson)
http://www.mercury.csse.unimelb.edu.au/
146
Herunterladen