Deklarative
(= fortgeschrittene) Programmierung
Vorlesung
WS 09,10; SS 12–14, 16
Johannes Waldmann, HTWK Leipzig 13. Juli 2016
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 1 / 209
Einleitung
Formen der deklarativen Programmierung
I funktionale Programmierung:
foldr (+) 0 [1,2,3]
foldr f z l = case l of
[] -> z ; (x:xs) -> f x (foldr f z xs)
I logische Programmierung:
append(A,B,[1,2,3]).
append([],YS,YS).
append([X|XS],YS,[X|ZS]):-append(XS,YS,ZS).
I Constraint-Programmierung
(set-logic QF_LIA) (set-option :produce-models true) (declare-fun a () Int) (declare-fun b () Int)
(assert (and (>= a 5) (<= b 30) (= (+ a b) 20))) (check-sat) (get-value (a b))
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 2 / 209
Einleitung
Definition
deklarativ: jedes (Teil-)Programm/Ausdruck hat einen Wert
(. . . und keine weitere (versteckte) Wirkung).
Werte k ¨onnen sein:
I “klassische” Daten (Zahlen, Listen, B ¨aume. . . )
I Funktionen (Sinus, . . . )
I Aktionen (Datei schreiben, . . . )
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 3 / 209
Einleitung
Softwaretechnische Vorteile
. . . der deklarativen Programmierung
I Beweisbarkeit: Rechnen mit Programmen wie in der Mathematik mit Termen
I Sicherheit: es gibt keine Nebenwirkungen und Wirkungen sieht man bereits am Typ
I Wiederverwendbarkeit: durch Entwurfsmuster (= Funktionen h ¨oherer Ordnung)
I Effizienz: durch Programmtransformationen im Compiler,
I Parallelisierbarkeit: durch Nebenwirkungsfreiheit
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 4 / 209
Einleitung
Beispiel Spezifikation/Test
import Test.SmallCheck
append :: forall t . [t] -> [t] -> [t]
append x y = case x of [] -> y
h : t -> h : append t y associative f =
\ x y z -> f x (f y z) == f (f x y) z test1 = smallCheckI
(associative (append::[Int]->[Int]->[Int])) Ubung: Kommutativit ¨at (formulieren und testen)¨
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 5 / 209
Einleitung
Beispiel Verifikation
app :: forall t . [t] -> [t] -> [t]
app x y = case x of [] -> y
h : t -> h : app t y Beweise
app x (app y z) == app (app x y) z Beweismethode: Induktion nach x.
I Induktionsanfang: x == [] . . .
I Induktionsschritt: x == h : t . . .
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 6 / 209
Einleitung
Beispiel Parallelisierung (Haskell)
Klassische Implementierung von Mergesort sort :: Ord a => [a] -> [a]
sort [] = [] ; sort [x] = [x]
sort xs = let ( left,right ) = split xs sleft = sort left
sright = sort right in merge sleft sright wird parallelisiert durch Annotationen:
sleft = sort left
‘using‘ rpar ‘dot‘ spineList sright = sort right ‘using‘ spineList vgl. http://thread.gmane.org/gmane.comp.
lang.haskell.parallel/181/focus=202
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 7 / 209
Einleitung
Beispiel Parallelisierung (C#, PLINQ)
I Die Anzahl der 1-Bits einer nichtnegativen Zahl:
Func<int,int>f =
x=>{int s=0; while(x>0){s+=x%2;x/=2;}return s;}
I
226−1
X
x=0
f(x)
Enumerable.Range(0,1<<26).Select(f).Sum()
I automatische parallele Auswertung, Laufzeitvergleich:
Time(()=>Enumerable.Range(0,1<<26).Select(f).Sum()) Time(()=>Enumerable.Range(0,1<<26).AsParallel()
.Select(f).Sum())
vgl. Introduction to PLINQ
https://msdn.microsoft.com/en-us/
library/dd997425(v=vs.110).aspx
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 8 / 209
Einleitung
Softwaretechnische Vorteile
. . . der statischen Typisierung
The language in which you write profoundly affects the design of programs written in that language.
For example, in the OO world, many people use UML to sketch a design. In Haskell or ML, one writes type signatures instead.
Much of the initial design phase of a
functional program consists of writing type definitions.
Unlike UML, though, all this design is incorporated in the final product, and is machine-checked throughout.
Simon Peyton Jones, in: Masterminds of Programing, 2009; http:
//shop.oreilly.com/product/9780596515171.do
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 9 / 209
Einleitung
Deklarative Programmierung in der Lehre
I funktionale Programmierung: diese Vorlesung
I logische Programmierung: in Angew. K ¨unstl.
Intell.
I Constraint-Programmierung: als Master-Wahlfach
Beziehungen zu weiteren LV: Voraussetzungen
I B ¨aume, Terme (Alg.+DS, Grundlagen Theor.
Inf.)
I Logik (Grundlagen TI, Softwaretechnik) Anwendungen:
I Softwarepraktikum
I weitere Sprachkonzepte in Prinzipien v.
Programmiersprachen
I Programmverifikation (vorw. f. imperative Programme)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 10 / 209
Einleitung
Konzepte und Sprachen
Funktionale Programmierung ist ein Konzept.
Realisierungen:
I in prozeduralen Sprachen:
I Unterprogramme als Argumente (in Pascal)
I Funktionszeiger (in C)
I in OO-Sprachen: Befehlsobjekte
I Multi-Paradigmen-Sprachen:
I Lambda-Ausdr ¨ucke in C#, Scala, Clojure
I funktionale Programmiersprachen (LISP, ML, Haskell)
Die Erkenntnisse sind sprachunabh ¨angig.
I A good programmer can write LISP in any language.
I Learn Haskell and become a better Java programmer.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 11 / 209
Einleitung
Gliederung der Vorlesung
I Terme, Termersetzungssysteme algebraische Datentypen, Pattern Matching, Persistenz
I Funktionen (polymorph, h ¨oherer Ordnung), Lambda-Kalk ¨ul, Rekursionsmuster
I Typklassen zur Steuerung der Polymorphie
I Bedarfsauswertung, unendl. Datenstrukturen (Iterator-Muster)
I weitere Entwurfsmuster
I Code-Qualit ¨at, Code-Smells, Refactoring
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 12 / 209
Einleitung
Softwaretechnische Aspekte
I algebraische Datentypen, Pattern Matching, Termersetzungssysteme
Scale: case class, Java: Entwurfsmuster Kompositum,
immutable objects, das Datenmodell von Git
I Funktionen (h ¨oherer Ordnung), Lambda-Kalk ¨ul, Rekursionsmuster
Lambda-Ausdr ¨ucke in C#, Entwurfsmuster Besucher
Codequalit ¨at, code smells, Refaktorisierung
I Typklassen zur Steuerung der Polymorphie
Interfaces in Java/C# , automatische Testfallgenerierung
I Bedarfsauswertung, unendl. Datenstrukturen
Iteratoren, Str ¨ome, LINQ
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 13 / 209
Einleitung
Organisation der LV
I jede Woche eine Vorlesung, eine ¨Ubung
I Hausaufgaben (teilw. autotool)
https://autotool.imn.htwk-leipzig.
de/shib/cgi-bin/Super.cgi
Identifizierung und Authentifizierung ¨uber Shibboleth-IDP des HTWK-Rechenzentrums, wie bei OPAL
I Pr ¨ufungszulassung: regelm ¨aßiges (d.h.
innerhalb der jeweiligen Deadline) und erfolgreiches (ingesamt ≥ 50%der Pflichtaufgaben) Bearbeiten von Ubungsaufgaben.¨
I Pr ¨ufung: Klausur (ohne Hilfsmittel)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 14 / 209
Einleitung
Literatur
I Skripte:
I aktuelles Semester http://www.imn.
htwk-leipzig.de/˜waldmann/lehre.html
I vorige Semester
http://www.imn.htwk-leipzig.de/
˜waldmann/lehre-alt.html
I Entwurfsmuster:
http://www.imn.htwk-leipzig.de/
˜waldmann/draft/pub/hal4/emu/
I Maurice Naftalin und Phil Wadler: Java Generics and Collections, O’Reilly 2006
I http://haskell.org/ (Sprache, Werkzeuge, Tutorials),
http://book.realworldhaskell.org/
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 15 / 209
Einleitung
Ubungen ¨
I im Pool Z430, vgl. http://www.imn.
htwk-leipzig.de/˜waldmann/etc/pool/
I Beispiele f. deklarative Programmierung
I funktional: Haskell mit ghci,
I logisch: Prolog mit swipl,
I constraint: mit mathsat, z3
I Haskell-Entwicklungswerkzeuge
I (eclipsefp, leksah, . . . ,http://xkcd.org/378/)
I API-Suchmaschine
http://www.haskell.org/hoogle/
I Commercial Uses of Functional Programming http://www.syslog.cl.cam.ac.uk/
2013/09/22/liveblogging-cufp-2013/
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 16 / 209
Daten
Wiederholung: Terme
I (Pr ¨adikatenlogik) Signatur Σ ist Menge von Funktionssymbolen mit Stelligkeiten
ein Term t in Signatur Σ ist
I Funktionssymbolf ∈Σder Stelligkeitk
mit Argumenten(t1, . . . ,tk), die selbst Terme sind.
Term(Σ) = Menge der Terme ¨uber Signatur Σ
I (Graphentheorie) ein Term ist ein
gerichteter, geordneter, markierter Baum
I (Datenstrukturen)
I Funktionssymbol=Konstruktor, Term=Baum
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 17 / 209
Daten
Beispiele: Signatur, Terme
I Signatur: Σ1 = {Z/0,S/1,f/2}
I Elemente von Term(Σ1):
Z(), S(S(Z())), f(S(S(Z())),Z())
I Signatur: Σ2 = {E/0,A/1,B/1}
I Elemente von Term(Σ2): . . .
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 18 / 209
Daten
Algebraische Datentypen
data Foo = Foo { bar :: Int, baz :: String } deriving Show
Bezeichnungen (benannte Notation)
I data Foo ist Typname
I Foo { .. } ist Konstruktor
I bar, baz sind Komponenten x :: Foo
x = Foo { bar = 3, baz = "hal" } Bezeichnungen (positionelle Notation)
data Foo = Foo Int String y = Foo 3 "bar"
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 19 / 209
Daten
Datentyp mit mehreren Konstruktoren
Beispiel (selbst definiert)
data T = A { foo :: Int }
| B { bar :: String, baz :: Bool } deriving Show
Bespiele (in Prelude vordefiniert) data Bool = False | True
data Ordering = LT | EQ | GT
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 20 / 209
Daten
Mehrsortige Signaturen
I (bisher) einsortige Signatur
Abbildung von Funktionssymbol nach Stelligkeit
I (neu) mehrsortige Signatur
I Menge von SortensymbolenS ={S1, . . .}
I Abb. von F.-Symbol nach Typ
I Typist Element ausS∗ ×S
Folge der Argument-Sorten, Resultat-Sorte
Bsp.: S = {Z,B},Σ ={0 7→([],Z),p 7→ ([Z,Z],Z), e 7→ ([Z,Z],B),a 7→ ([B,B],B)}.
I Term(Σ): konkrete Beispiele, allgemeine Definition?
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 21 / 209
Daten
Rekursive Datentypen
data Tree = Leaf {}
| Branch { left :: Tree , right :: Tree } Ubung: Objekte dieses Typs erzeugen¨ (benannte und positionelle Notation der Konstruktoren)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 22 / 209
Daten
Daten mit Baum-Struktur
I mathematisches Modell: Term ¨uber Signatur
I programmiersprachliche Bezeichnung:
algebraischer Datentyp (die Konstruktoren bilden eine Algebra)
I praktische Anwendungen:
I Formel-B ¨aume (in Aussagen- und Pr ¨adikatenlogik)
I Suchb ¨aume (in VL Algorithmen und
Datenstrukturen, injava.util.TreeSet<E>)
I DOM (Document Object Model) https://www.w3.org/DOM/DOMTR
I JSON (Javascript Object Notation) z.B. f ¨ur AJAX http://www.ecma-international.org/
publications/standards/Ecma-404.htm
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 23 / 209
Daten
Bezeichnungen f ¨ur Teilterme
I Position: Folge von nat ¨urlichen Zahlen
(bezeichnet einen Pfad von der Wurzel zu einem Knoten)
Beispiel: f ¨ur t = S(f(S(S(Z())),Z())) ist [0,1] eine Position in t.
I Pos(t) = die Menge der Positionen eines Terms t
Definition: wenn t = f(t1, . . . ,tk),
dann Pos(t) = {[]} ∪ {[i −1]++p | 1 ≤i ≤ k ∧p ∈ Pos(ti)}.
dabei bezeichnen:
I [] die leere Folge,
I [i] die Folge der L ¨ange 1 mit Element i,
I ++ den Verkettungsoperator f ¨ur Folgen
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 24 / 209
Daten
Operationen mit (Teil)Termen
I t[p] = der Teilterm von t an Position p Beispiel: S(f(S(S(Z())),Z()))[0,1] = . . .
Definition (durch Induktion ¨uber die L ¨ange von p): . . .
I t[p := s] : wie t, aber mit Terms an Position p Beispiel:
S(f(S(S(Z())),Z()))[[0,1] := S(Z)]x = . . . Definition (durch Induktion ¨uber die L ¨ange von p): . . .
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 25 / 209
Daten
Operationen mit Variablen in Termen
I Term(Σ,V) = Menge der Terme ¨uber Signatur Σ mit Variablen aus V
Beispiel: Σ ={Z/0,S/1,f/2},V = {y}, f(Z(),y) ∈ Term(Σ,V).
I Substitution σ: partielle Abbildung V → Term(Σ) Beispiel: σ1 = {(y,S(Z()))}
I eine Substitution auf einen Term anwenden: tσ:
Intuition: wie t, aber stattv immer σ(v) Beispiel: f(Z(),y)σ1 = f(Z(),S(Z())) Definition durch Induktion ¨uber t
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 26 / 209
Daten
Termersetzungssysteme
I Daten = Terme (ohne Variablen)
I Programm R = Menge von Regeln
Bsp: R = {(f(Z(),y),y), (f(S(x),y),S(f(x,y)))}
I Regel = Paar(l,r) von Termen mit Variablen
I Relation →R ist Menge aller Paare (t,t0) mit
I es existiert(l,r)∈R
I es existiert Positionp int
I es existiert Substitution
σ : (Var(l)∪Var(r))→Term(Σ)
I so daßt[p] =lσundt0 =t[p :=rσ].
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 27 / 209
Daten
Termersetzungssysteme als Programme
I →R beschreibt einen Schritt der Rechnung von R,
I transitive und reflexive H ¨ulle →∗R beschreibt Folge von Schritten.
I Resultat einer Rechnung ist Term in R-Normalform
(:= ohne→R-Nachfolger)
dieses Berechnungsmodell ist im allgemeinen
I nichtdeterministisch
R1 = {C(x,y) → x,C(x,y) → y}
(ein Term kann mehrere →R-Nachfolger haben, ein Term kann mehrere Normalformen
erreichen)
I nicht terminierend R2 = {p(x,y) →p(y,x)}
(es gibt eine unendliche Folge von
→R-Schritten,
es kann Terme ohne Normalform geben)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 28 / 209
Daten
Konstruktor-Systeme
F ¨ur TRS R ¨uber Signatur Σ: Symbol s ∈ Σ heißt
I definiert, wenn ∃(l,r) ∈ R : l[] = s(. . .) (das Symbol in der Wurzel ist s)
I sonst Konstruktor.
Das TRS R heißt Konstruktor-TRS, falls:
I definierte Symbole kommen links nur in den Wurzeln vor
Ubung: diese Eigenschaft formal spezifizieren¨ Beispiele: R1 = {a(b(x)) → b(a(x))} ¨uber Σ1 = {a/1,b/1},
R2 = {f(f(x,y),z) → f(x,f(y,z)) ¨uberΣ2 = {f/2}:
definierte Symbole? Konstruktoren?
Konstruktor-System?
Funktionale Programme sind ¨ahnlich zu Konstruktor-TRS.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 29 / 209
Daten
Ubung Terme, TRS ¨
I Geben Sie die Signatur des Terms √
a·a+b·b an.
I Geben Sie ein Element
t ∈ Term({f/1,g/3,c/0}) an mitt[1] = c().
mit ghci:
I
data T = F T | G T T T | C deriving Show erzeugen Sie o.g. Terme (durch
Konstruktoraufrufe)
Die Gr ¨oße eines Terms t ist definiert durch
|f(t1, . . . ,tk)| = 1+ Pk
i=1|ti|.
I Bestimmen Sie |√
a·a+b ·b|.
I Beweisen Sie ∀Σ : ∀t ∈ Term(Σ) : |t|= |Pos(t)|.
Vervollst ¨andigen Sie die Definition der Tiefe von Termen:
depth(f()) = 0
k > 0 ⇒ depth(f(t1, . . . ,tk)) = . . .
I Bestimmen Sie depth(√
a·a+b ·b)
I Beweisen Sie ∀Σ : ∀t ∈ Term(Σ) : depth(t) < |t|.
F ¨ur die Signatur Σ = {Z/0,S/1,f/2}:
I f ¨ur welche Substitution σ gilt f(x,Z)σ = f(S(Z),Z)?
I f ¨ur dieses σ: bestimmen Sie f(x,S(x))σ.
Notation f ¨ur Termersetzungsregeln: anstatt (l,r) schreibe l →r.
Abk ¨urzung f ¨ur Anwendung von 0-stelligen Symbolen: anstatt Z() schreibe Z.
I F ¨ur R = {f(S(x),y) → f(x,S(y)),f(Z,y) → y} bestimme alle R-Normalformen von
f(S(Z),S(Z)).
I f ¨ur Rd = R∪ {d(x) → f(x,x)}
bestimme alle Rd-Normalformen von d(d(S(Z))).
I Bestimme die Signatur Σd von Rd.
Bestimme die Menge der Terme aus Term(Σd), die Rd-Normalformen sind.
I f ¨ur die Signatur {A/2,D/0}:
definiere Terme t0 = D,ti+1 = A(ti,D).
Zeichne t3. Bestimme|ti| .
I f ¨ur S = {A(A(D,x),y) → A(x,A(x,y))}
bestimme S-Normalform(en), soweit existieren, der Terme t2,t3,t4. Zusatz: von ti allgemein.
Abk ¨urzung f ¨ur mehrfache Anwendung eines einstelligen Symbols: A(A(A(A(x)))) = A4(x)
I f ¨ur {A(B(x)) → B(A(x))}
¨uber Signatur{A/1,B/1,E/0}:
bestimme Normalform von Ak(Bk(E)) f ¨ur k = 1,2,3, allgemein.
I f ¨ur {A(B(x)) → B(B(A(x)))}
¨uber Signatur{A/1,B/1,E/0}:
bestimme Normalform von Ak(B(E)) f ¨ur k = 1,2,3, allgemein.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 30 / 209
Programme
Funktionale Programme
. . . sind spezielle Term-Ersetzungssysteme. Beispiel:
Signatur: S einstellig, Z nullstellig, f zweistellig.
Ersetzungssystem
{f(Z,y) → y,f(S(x0),y) → S(f(x0,y))}.
Startterm f(S(S(Z)),S(Z)).
entsprechendes funktionales Programm:
data N = Z | S N f :: N -> N -> N f x y = case x of
{ Z -> y ; S x’ -> S (f x’ y) }
Aufruf: f (S (S Z)) (S Z)
Auswertung = Folge von Ersetzungsschritten →∗R Resultat = Normalform (hat keine →R-Nachfolger)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 31 / 209
Programme
Pattern Matching
data Tree = Leaf | Branch Tree Tree size :: Tree -> Int
size t = case t of { ... ; Branch l r -> ... }I Syntax allgemein:
case t of { <Muster> -> <Ausdruck> ; ... }
I <Muster> enth ¨alt Konstruktoren und Variablen, entspricht linker Seite einer
Term-Ersetzungs-Regel, <Ausdruck>
entspricht rechter Seite
I Def.: t paßt zum Muster l: es existiert σ mit lσ = t
I dynamische Semantik: f ¨ur das erste passende Muster wird rσ ausgewertet
I statische Semantik: jedes <Muster> hat gleichen Typ wie t, alle <Ausdruck> haben
¨ubereinstimmenden Typ.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 32 / 209
Programme
Eigenschaften von Case-Ausdr ¨ucken
ein case-Ausdruck heißt
I disjunkt, wenn die Muster nicht ¨uberlappen (es gibt keinen Term, der zu mehr als 1 Muster paßt)
I vollst ¨andig, wenn die Muster den gesamten Datentyp abdecken
(es gibt keinen Term, der zu keinem Muster paßt)
Bespiele (f ¨ur data N = F N N | S N | Z) -- nicht disjunkt:
case t of { F (S x) y -> .. ; F x (S y) -> .. } -- nicht vollst¨andig:
case t of { F x y -> .. ; Z -> .. }
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 33 / 209
Programme
data und case
typisches Vorgehen beim Verarbeiten algebraischer Daten vom Typ T:
I F ¨ur jeden Konstruktor des Datentyps data T = C1 ...
| C2 ...
I schreibe einen Zweig in der Fallunterscheidung f x = case x of
C1 ... -> ...
C2 ... -> ...
I Argumente der Konstruktoren sind Variablen ⇒ Case-Ausdruck ist disjunkt und vollst ¨andig.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 34 / 209
Programme
Peano-Zahlen
data N = Z | S N plus :: N -> N -> N plus x y = case x of
Z -> y
S x’ -> S (plus x’ y) Aufgaben:
I implementiere Multiplikation, Potenz
I beweise die ¨ublichen Eigenschaften (Addition, Multiplikation sind assoziativ, kommutativ, besitzen neutrales Element)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 35 / 209
Programme
Pattern Matching in versch. Sprachen
I Scala: case classes
http://docs.scala-lang.org/
tutorials/tour/case-classes.html
I C# (7): https://github.com/dotnet/
roslyn/blob/features/patterns/docs/
features/patterns.md
I Javascript?
Nicht verwechseln mit regular expression matching zur String-Verarbeitung. Es geht um algebraische (d.h. baum-artige) Daten!
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 36 / 209
Programme
Ubung Pattern Matching, Programme ¨
I F ¨ur die Deklarationen
-- data Bool = False | True (aus Prelude) data T = F T | G T T T | C
entscheide/bestimme f ¨ur jeden der folgenden Ausdr ¨ucke:
I syntaktisch korrekt?
I statisch korrekt?
I Resultat (dynamische Semantik)
I disjunkt? vollst ¨andig?
1. case False of { True -> C } 2. case False of { C -> True } 3. case False of { False -> F F }
4. case G (F C) C (F C) of { G x y z -> F z } 5. case F C of { F (F x) -> False }
6. case F C of { F x -> False ; True -> False } 7. case True of { False -> C ; True -> F C } 8. case True of { False -> C ; False -> F C }
9. case C of { G x y z -> False; F x -> False; C -> True }
I Operationen auf Wahrheitswerten:
import qualified Prelude
data Bool = False | True deriving Prelude.Show not :: Bool -> Bool -- Negation
not x = case x of ... -> ...
... -> ...
Syntax: wenn nach of kein {folgt:
implizite { ; }durch Abseitsregel (layout rule).
I (&&) :: Bool -> Bool -> Bool x && y = case ... of ...
Syntax: Funktionsname
I beginnt mit Buchstabe: steht vor Argumenten,
I beginnt mit Zeichen: zwischen Argumenten (als Operator)
Operator als Funktion: (&&) False True, Funktion als Operator: True ‘f‘ False.
I Listen von Wahrheitswerten:
data List = Nil | Cons Bool List deriving Prelude.Show and :: List -> Bool
and l = case l of ...
entsprechend or :: List -> Bool
I (Wdhlg.) welche Signatur beschreibt bin ¨are B ¨aume
(jeder Knoten hat 2 oder 0 Kinder, die B ¨aume sind; es gibt keine Schl ¨ussel)
I geben Sie die dazu ¨aquivalente
data-Deklaration an: data T = ...
I implementieren Sie daf ¨ur die Funktionen size :: T -> Prelude.Int
depth :: T -> Prelude.Int
benutze Prelude.+ (das ist Operator), Prelude.min, Prelude.max
I f ¨ur Peano-Zahlen data N = Z | S N implementieren Sie plus, mal, min, max
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 37 / 209
Polymorphie
Definition, Motivation
I Beispiel: bin ¨are B ¨aume mit Schl ¨ussel vom Typ e data Tree e = Leaf
| Branch (Tree e) e (Tree e) Branch Leaf True Leaf :: Tree Bool
Branch Leaf 42 Leaf :: Tree Int
I Definition:
ein polymorpher Datentyp ist ein Typkonstruktor (= eine Funktion, die Typen auf einen Typ
abbildet)
I unterscheide: Tree ist der Typkonstruktor, Branch ist ein Datenkonstruktor
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 38 / 209
Polymorphie
Beispiele f. Typkonstruktoren (I)
I Kreuzprodukt:
data Pair a b = Pair a b
I disjunkte Vereinigung:
data Either a b = Left a | Right b
I data Maybe a = Nothing | Just a
I Haskell-Notation f ¨ur Produkte:
(1,True)::(Int,Bool) f ¨ur 0,2,3, . . . Komponenten
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 39 / 209
Polymorphie
Beispiele f. Typkonstruktoren (II)
I bin ¨are B ¨aume
data Bin a = Leaf
| Branch (Bin a) a (Bin a)
I Listen
data List a = Nil
| Cons a (List a)
I B ¨aume
data Tree a = Node a (List (Tree a))
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 40 / 209
Polymorphie
Polymorphe Funktionen
Beispiele:
I Spiegeln einer Liste:
reverse :: forall e . List e -> List e
I Verketten von Listen mit gleichem Elementtyp:
append :: forall e . List e -> List e -> List e
Knotenreihenfolge eines Bin ¨arbaumes:
preorder :: forall e . Bin e -> List e Def: der Typ einer polymorphen Funktion beginnt mit All-Quantoren f ¨ur Typvariablen.
Bsp: Datenkonstruktoren polymorpher Typen.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 41 / 209
Polymorphie
Bezeichnungen f. Polymorphie
data List e = Nil | Cons e (List e)
I List ist ein Typkonstruktor
I List e ist ein polymorpher Typ (ein Typ-Ausdruck mit Typ-Variablen)
I List Bool ist ein monomorpherTyp
(entsteht durch Instantiierung: Substitution der Typ-Variablen durch Typen)
I polymorphe Funktion:
reverse:: forall e . List e -> List e monomorphe Funktion:
xor:: List Bool -> Bool polymorphe Konstante:
Nil::forall e. List e
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 42 / 209
Polymorphie
Operationen auf Listen (I)
data List a = Nil | Cons a (List a)
I append xs ys = case xs of Nil ->
Cons x xs’ ->
I Ubung: formuliere und beweise:¨ append ist assoziativ.
I reverse xs = case xs of Nil ->
Cons x xs’ ->
I beweise:
forall xs . reverse (reverse xs) == xs
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 43 / 209
Polymorphie
Operationen auf Listen (II)
Die vorige Implementierung von reverse ist (f ¨ur einfach verkettete Listen) nicht effizient.
Besser ist:
reverse xs = rev_app xs Nil mit Spezifikation
rev_app xs ys = append (reverse xs) ys Ubung: daraus die Implementierung von¨ rev_app ableiten
rev_app xs ys = case xs of ...
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 44 / 209
Polymorphie
Operationen auf B ¨aumen
data List e = Nil | Cons e (List e)
data Bin e = Leaf | Branch (Bin e) e (Bin e) Knotenreihenfolgen
I preorder :: forall e . Bin e -> List e preorder t = case t of ...
I entsprechend inorder, postorder
I und Rekonstruktionsaufgaben
Adressierug von Knoten (False= links,True = rechts)
I get :: Tree e -> List Bool -> Maybe e
I positions :: Tree e -> List (List Bool)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 45 / 209
Polymorphie
Ubung Polymorphie ¨
Geben Sie alle Elemente dieser Datentypen an:
I Maybe ()
I Maybe (Bool, Maybe ())
I
Either (Bool,Bool) (Maybe (Maybe Bool)) Operationen auf Listen:
I append, reverse, rev app Operationen auf B ¨aumen:
I preorder, inorder, postorder, (Rekonstruktion)
I get, (positions)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 46 / 209
Polymorphie
Kochrezept: Objektkonstruktion
Aufgabe (Bsp):
x :: Either (Maybe ()) (Pair Bool ()) L ¨osung (Bsp):
I der Typ Either a b hat Konstruktoren Left a | Right b. W ¨ahle Right b.
Die Substitution f ¨ur die Typvariablen ist a = Maybe (), b = Pair Bool ().
x = Right y mit y :: Pair Bool ()
I der Typ Pair a b hat Konstruktor Pair a b.
die Substitution f ¨ur diese Typvariablen ist a = Bool, b = ().
y = Pair p q mit p :: Bool, q :: ()
I der Typ Boolhat Konstruktoren
False | True, w ¨ahle p = False. der Typ () hat Konstruktor (), also q=()
Insgesamt
x = Right y = Right (Pair False ()) Vorgehen (allgemein)
I bestimme den Typkonstruktor
I bestimme die Substitution f ¨ur die Typvariablen
I w ¨ahle einen Datenkonstruktor
I bestimme Anzahl und Typ seiner Argumente
I w ¨ahle Werte f ¨ur diese Argumente nach diesem Vorgehen.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 47 / 209
Polymorphie
Kochrezept: Typ-Bestimmung
Aufgabe (Bsp.) bestimme Typ von x (erstes Arg. von get):
at :: Position -> Tree a -> Maybe a at p t = case t of
Node f ts -> case p of Nil -> Just f
Cons x p’ -> case get x ts of Nothing -> Nothing
Just t’ -> at p’ t’
L ¨osung:
I bestimme das Muster, durch welches x deklariert wird.
L ¨osung: Cons x p’ ->
I bestimme den Typ diese Musters
L ¨osung: ist gleich dem Typ der zugeh ¨origen Diskriminante p
I bestimme das Muster, durch das p deklariert wird
L ¨osung: at p t =
I bestimme den Typ von p
L ¨osung: durch Vergleich mit Typdeklaration von at (p ist das erste Argument) p :: Position, also Cons x p’ :: Position = List N, also x :: N.
Vorgehen zur Typbestimmung eines Namens:
I finde die Deklaration (Muster einer Fallunterscheidung oder einer Funktionsdefinition)
I bestimme den Typ des Musters
(Fallunterscheidung: Typ der Diskriminante, Funktion: deklarierter Typ)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 48 / 209
Polymorphie
Statische Typisierung und Polymorphie
Def: dynamische Typisierung:
I die Daten (zur Laufzeit des Programms, im Hauptspeicher) haben einen Typ
Def: statische Typisierung:
I Bezeichner, Ausdr ¨ucke (im Quelltext) haben einen Type (zur ¨Ubersetzungszeit bestimmt).
I f ¨ur jede Ausf ¨uhrung des Programms gilt: der statische Typ eines Ausdrucks ist gleich dem dynamischen Typ seines Wertes
Bsp. f ¨ur Programm ohne statischen Typ (Javascript) function f (x) {
if (x>0) { return function () { return 42; } } else { return "foobar"; } }
Dann: Auswertung von f(1)() ergibt 42,
Auswertung von f(0)() ergibt Laufzeit-Typfehler.
entsprechendes Haskell-Programm ist statisch fehlerhaft
f x = case x > 0 of True -> \ () -> 42 False -> "foobar"
Nutzen der statischen Typisierung:
I beim Programmieren: Entwurfsfehler werden zu Typfehlern, diese werden zur Entwurfszeit
automatisch erkannt ⇒ fr ¨uher erkannte Fehler lassen sich leichter beheben
I beim Ausf ¨uhren: es gibt keine Lauzeit-Typfehler
⇒ keine Typpr ¨ufung zur Laufzeit n ¨otig, effiziente Ausf ¨uhrung
Nutzen der Polymorphie:
I Flexibilit ¨at, nachnutzbarer Code, z.B. Anwender einer Collection-Bibliothek legt Element-Typ fest (Entwickler der Bibliothek kennt den
Element-Typ nicht)
I gleichzeitig bleibt statische Typsicherheit erhalten
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 49 / 209
Polymorphie
Von der Spezifikation zur Implementierung (I)
Bsp: Addition von Peano-Zahlen data N = Z | S N
plus :: N -> N -> N
aus der Typdeklaration wird abgeleitet:
plus x y = case x of Z ->
S x’ ->
erster Zweig: plus Z y = 0 + y = y zweiter Zweig :
plus (S x’) y = (1 + x’) + y = mit Assoziativit ¨at von + gilt
... = 1 + (x’ + y) = S (plus x’ y) Bsp. ( ¨U): Multiplikation. Hinweis: benutze Distributivgesetz.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 50 / 209
Polymorphie
Von der Spezifikation zur Implementierung (II)
Bsp: homogene Listen
data List a = Nil | Cons a (List a) Aufgabe: implementiere
maximum :: List N -> N Spezifikation:
maximum (Cons x1 Nil) = x1
maximum (append xs ys) = max (maximum xs) (maximum ys)
I substitutiere xs = Nil, erhalte
maximum (append Nil ys) = maximum ys
= max (maximum Nil) (maximum ys) d.h. maximum Nil sollte das neutrale Element f ¨ur max (auf nat ¨urlichen Zahlen) sein, also 0 (geschrieben Z).
I substitutiere xs = Cons x1 Nil, erhalte maximum (append (Cons x1 Nil) ys)
= maximum (Cons x1 ys)
= max (maximum (Cons x1 Nil)) (maximum ys)
= max x1 (maximum ys)
Damit kann der aus dem Typ abgeleitete Quelltext maximum :: List N -> N
maximum xs = case xs of Nil ->
Cons x xs’ ->
erg ¨anzt werden.
Vorsicht: f ¨ur min, minimum funktioniert das nicht so, denn minhat f ¨ur N kein neutrales Element.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 51 / 209
Unver ¨anderliche Objekte
Uberblick ¨
I alle Attribute aller Objekte sind unver ¨anderlich (final)
I anstatt Objekt zu ¨andern, konstruiert man ein neues
Eigenschaften des Programmierstils:
I vereinfacht Formulierung und Beweis von Objekteigenschaften
I parallelisierbar (keine updates, keinedata races) http://fpcomplete.com/
the-downfall-of-imperative-programming/
I Persistenz (Verf ¨ugbarkeit fr ¨uherer Versionen)
I Belastung des Garbage Collectors (. . . daf ¨ur ist er da)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 52 / 209
Unver ¨anderliche Objekte
Beispiel: Einf ¨ugen in Baum
I destruktiv:
interface Tree<K> { void insert (K key); } Tree<String> t = ... ;
t.insert ("foo");
I persistent (Java):
interface Tree<K> { Tree<K> insert (K key); } Tree<String> t = ... ;
Tree<String> u = t.insert ("foo");
I persistent (Haskell):
insert :: Tree k -> k -> Tree k
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 53 / 209
Unver ¨anderliche Objekte
Beispiel: (unbalancierter) Suchbaum
data Tree k = Leaf
| Branch (Tree k) k (Tree k) insert :: Ord k => k -> Tree k -> Tree k insert k t = case t of ...
Diskussion:
I Ord k entspricht
K implements Comparable<K>, genaueres sp ¨ater (Haskell-Typklassen)
I wie teuer ist die Persistenz?
(wieviel M ¨ull entsteht bei einem insert?)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 54 / 209
Unver ¨anderliche Objekte
Beispiel: Sortieren mit Suchb ¨aumen
data Tree k = Leaf
| Branch (Tree k) k (Tree k) insert :: Ord k => k -> Tree k -> Tree k build :: Ord k => [k] -> Tree k
build = foldr ... ...
sort :: Ord k => [k] -> [k]
sort xs = ... ( ... xs )
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 55 / 209
Unver ¨anderliche Objekte
Persistente Objekte in Git
http://git-scm.com/
I Distributed development.
I Strong support for non-lineardevelopment.
(Branching and merging are fast and easy.)
I Efficient handling of large projects.
(z. B. Linux-Kernel, http://kernel.org/ )
I Toolkit design.
I Cryptographic authentication of history.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 56 / 209
Unver ¨anderliche Objekte
Objekt-Versionierung in Git
I Objekt-Typen:
I Datei (blob),
I Verzeichnis (tree), mit Verweisen auf blobs und trees
I Commit, mit Verweisen auf tree u. commits (Vorg ¨anger)
git cat-file -p <hash>
I Objekte sind unver ¨anderlich und durch SHA1-Hash (160 bit = 40 Hex-Zeichen) identifiziert
I statt ¨Uberschreiben: neue Objekte anlegen
I jeder Zustand ist durch Commit-Hash (weltweit) eindeutig beschrieben und kann
wiederhergestellt werden
Quelltexte zur Vorlesung: https://gitlab.imn.
htwk-leipzig.de/waldmann/fop-ss16
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 57 / 209
Funktionen
Funktionen als Daten
bisher:
f :: Int -> Int f x = 2 * x + 5
¨aquivalent: Lambda-Ausdruck f = \ x -> 2 * x + 5
Lambda-Kalk ¨ul: Alonzo Church 1936, Henk Barendregt 198*, . . .
Funktionsanwendung:
(\ x -> B) A = B [x := A]
ist nur erlaubt, falls keine in A freie Variable durch ein Lambda in B gebunden wird.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 58 / 209
Funktionen
Der Lambda-Kalk ¨ul
. . . als weiteres Berechnungsmodell,
(vgl. Termersetzungssysteme, Turingmaschine, Random-Access-Maschine)
Syntax: die Menge der Lambda-TermeΛ ist
I jede Variable ist ein Term: v ∈ V ⇒v ∈ Λ
I Funktionsanwendung (Applikation):
F ∈ Λ,A ∈ Λ ⇒(FA) ∈ Λ
I Funktionsdefinition (Abstraktion):
v ∈ V,B ∈ Λ⇒ (λv.B) ∈ Λ Semantik: eine Relation→β auf Λ (vgl. →R f ¨ur TermersetzungssystemR)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 59 / 209
Funktionen
Freie und gebundene Variablen(vorkommen)
I Das Vorkommen von v ∈ V an Position p in Term t heißt frei, wenn
”dar ¨uber kein λv. . . . steht“
I Def. fvar(t) =Menge der in t frei vorkommenden Variablen (definiere durch strukturelle Induktion)
I Eine Variable x heißt in A gebunden, falls A einen Teilausdruck λx.B enth ¨alt.
I Def. bvar(t) = Menge der int gebundenen Variablen
Bsp: fvar(x(λx.λy.x)) = {x}, bvar(x(λx.λy.x)) = {x,y},
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 60 / 209
Funktionen
Semantik des Lambda-Kalk ¨uls:
Reduktion →
βRelation →β auf Λ (ein Reduktionsschritt) Es gilt t →β t0, falls
I ∃p ∈ Pos(t), so daß
I t[p] = (λx.B)A mit bvar(B)∩fvar(A) = ∅
I t0 = t[p := B[x := A]]
dabei bezeichnet B[x := A] ein Kopie von B, bei der jedes freie Vorkommen von x durchA
ersetzt ist
Ein (Teil-)Ausdruck der Form (λx.B)A heißt Redex.
(Dort kann weitergerechnet werden.) Ein Term ohne Redex heißt Normalform.
(Normalformen sind Resultate von Rechnungen.)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 61 / 209
Funktionen
Semantik . . . : gebundene Umbenennung →
αI Relation →α auf Λ, beschreibt gebundene Umbenennung einer lokalen Variablen.
I Beispiel λx.fxz →α λy.fyz.
(f und z sind frei, k ¨onnen nicht umbenannt werden)
I Definition t →α t0:
I ∃p ∈Pos(t), so daßt[p] = (λx.B)
I y ∈/ bvar(B)∪fvar(B)
I t0 =t[p :=λy.B[x :=y]]
I wird angewendet, um bvar(B)∩ fvar(A) = ∅ in Regel f ¨ur →β zu erf ¨ullen.
Bsp: betrachte den unterstrichenen Redex in (λx.((λf.(λx.(x +f8)))(λy.(x + y))))3
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 62 / 209
Funktionen
Umbenennung von lokalen Variablen
int x = 3;
int f(int y) { return x + y; }
int g(int x) { return (x + f(8)); } // g(5) => 16
Darf f(8)ersetzt werden durch f[y := 8] ? - Nein:
int x = 3;
int g(int x) { return (x + (x+8)); } // g(5) => 18
Das freie x in (x + y) wird f ¨alschlich gebunden.
L ¨osung: lokal umbenennen
int g(int z) { return (z + f(8)); }
dann ist Ersetzung erlaubt
int x = 3;
int g(int z) { return (z + (x+8)); } // g(5) => 16
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 63 / 209
Funktionen
Lambda-Terme: verk ¨urzte Notation
I Applikation ist links-assoziativ, Klammern weglassen:
(. . .((FA1)A2). . .An) ∼FA1A2. . .An Beispiel: ((xz)(yz)) ∼xz(yz)
Wirkt auch hinter dem Punkt:
(λx.xx) bedeutet (λx.(xx)) — und nicht ((λx.x)x)
I geschachtelte Abstraktionen unter ein Lambda schreiben:
(λx1.(λx2. . . .(λxn.B). . .)) ∼λx1x2. . .xn.B Beispiel: λx.λy.λz.B ∼ λxyz.B
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 64 / 209
Funktionen
Ein- und mehrstellige Funktionen
eine einstellige Funktion zweiter Ordnung:
f = \ x -> ( \ y -> ( x*x + y*y ) ) Anwendung dieser Funktion:
(f 3) 4 = ...
Kurzschreibweisen (Klammern weglassen):
f = \ x y -> x * x + y * y ; f 3 4 Ubung:¨
gegeben t = \ f x -> f (f x) bestimme t succ 0, t t succ 0,
t t t succ 0, t t t t succ 0, ...
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 65 / 209
Funktionen
Typen
f ¨ur nicht polymorphe Typen: tats ¨achlicher
Argumenttyp muß mit deklariertem Argumenttyp
¨ubereinstimmen:
wenn f :: A → B und x ::A, dann(fx) :: B. bei polymorphen Typen k ¨onnen der Typ von f :: A → B und der Typ von x :: A0 Typvariablen enthalten.
Beispiel: λx.x :: ∀t.t → t.
Dann m ¨ussen A und A0 nicht ¨ubereinstimmen, sondern nur unifizierbar sein (eine gemeinsame Instanz besitzen).
Beispiel: (λx.x)True
benutze Typ-Substitution σ = {(t,Bool)}.
Bestimme allgemeinsten Typ von t = λfx.f(fx)), von (tt).
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 66 / 209
Funktionen
Beispiel f ¨ur Typ-Bestimmung
Aufgabe: bestimme den allgemeinsten Typ von λfx.f(fx)
I Ansatz mit Typvariablen f ::t1,x :: t2
I betrachte (fx): der Typ von f muß ein Funktionstyp sein, also t1 = (t11 →t12) mit neuen Variablen t11,t12.
Dann gilt t11 = t2 und (fx) :: t12.
I betrachte f(fx). Wir haben f ::t11 →t12 und (fx) :: t12, also folgt t11 = t12. Dann f(fx) :: t12.
I betrachte λx.f(fx).
Aus x :: t12 und f(fx) :: t12 folgt λx.f(fx) :: t12 → t12.
I betrachte λf.(λx.f(fx)).
Aus f ::t12 →t12 und λx.f(fx) :: t12 → t12 folgt λfx.f(fx) :: (t12 → t12) → (t12 → t12)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 67 / 209
Funktionen
Verk ¨urzte Notation f ¨ur Typen
I Der Typ-Pfeil ist rechts-assoziativ:
T1 → T2 → · · · → Tn →T bedeutet (T1 →(T2 → · · · → (Tn → T)· · ·))
I das paßt zu den Abk ¨urzungen f ¨ur mehrstellige Funktionen:
λ(x :: T1).λ(x ::T2).(B :: T) hat den Typ (T1 →(T2 →B)), mit o.g. Abk ¨urzung T1 →T2 →T.
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 68 / 209
Funktionen
Lambda-Ausdr ¨ucke in C#
I Beispiel (Fkt. 1. Ordnung)
Func<int,int> f = (int x) => x*x;
f (7);
I Ubung (Fkt. 2. Ordnung) — erg ¨anze alle Typen:¨
??? t = (??? g) => (??? x) => g (g (x));
t (f)(3);
I Anwendungen bei Streams, sp ¨ater mehr
(new int[]{3,1,4,1,5,9}).Select(x => x * 2);
(new int[]{3,1,4,1,5,9}).Where(x => x > 3);
I Ubung: Diskutiere statische/dynamische¨ Semantik von
(new int[]{3,1,4,1,5,9}).Select(x => x > 3);
(new int[]{3,1,4,1,5,9}).Where(x => x * 2);
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 69 / 209
Funktionen
Lambda-Ausdr ¨ucke in Java(8)
funktionales Interface (FI): hat genau eine Methode Lambda-Ausdruck (
”burger arrow“) erzeugt Objekt einer anonymen Klasse, die FI implementiert.
interface I { int foo (int x); } I f = (x)-> x+1;
System.out.println (f.foo(8));
vordefinierte FIs:
import java.util.function.*;
Function<Integer,Integer> g = (x)-> x*2;
System.out.println (g.apply(8));
Predicate<Integer> p = (x)-> x > 3;
if (p.test(4)) { System.out.println ("foo"); }
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 70 / 209
Funktionen
Lambda-Ausdr ¨ucke in Javascript
$ node
> var f = function (x){return x+3;}
undefined
> f(4) 7
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 71 / 209
Funktionen
Beispiele Fkt. h ¨oherer Ord.
I Haskell-Notation f ¨ur Listen:
data List a = Nil | Cons a (List a) data [a] = [] | a : [a]
I Verarbeitung von Listen:
filter :: (a -> Bool) -> [a] -> [a]
takeWhile :: (a -> Bool) -> [a] -> [a]
partition :: (a -> Bool) -> [a] -> ([a],[a])
I Vergleichen, Ordnen:
nubBy :: (a -> a -> Bool) -> [a] -> [a]
data Ordering = LT | EQ | GT minimumBy
:: (a -> a -> Ordering) -> [a] -> a
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 72 / 209
Funktionen
Ubung Lambda-Kalk ¨ul ¨
I Wiederholung: konkrete Syntax, abstrakte Syntax, Semantik
I S = λxyz.xz(yz),K = λab.a, Normalform von SKKc
I (mit data N=Z|S N) bestimme Normalform von ttSZ
f ¨ur t = λfx.f(fx),
I definiere Λals algebraischen Datentyp data L = ... (3 Konstruktoren) implementiere size :: L -> Int, depth :: L -> Int.
implementiere
bvar :: L -> S.Set String, fvar :: L -> S.Set String, siehe Folie mit Definitionen und dort angegebene Testf ¨alle
benutze
import qualified Data.Set as S, API-Dokumentation: https:
//hackage.haskell.org/package/
containers/docs/Data-Set.html
I autotool-Aufgaben Lambda-Kalk ¨ul
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 73 / 209
Funktionen
Ubung Fkt. h ¨oherer Ordnung ¨
I Typisierung, Beispiele in Haskell, C#, Java, Javascript
compose ::
compose = \ f g -> \ x -> f (g x)
I Implementierung von takeWhile, dropWhile
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 74 / 209
Rekursionsmuster
Rekursion ¨uber B ¨aume (Beispiele)
data Tree a = Leaf
| Branch (Tree a) a (Tree a) summe :: Tree Int -> Int
summe t = case t of Leaf -> 0
Branch l k r -> summe l + k + summe r preorder :: Tree a -> List a
preorder t = case t of Leaf -> Nil
Branch l k r ->
Cons k (append (preorder l) (preorder r))
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 75 / 209
Rekursionsmuster
Rekursion ¨uber B ¨aume (Schema)
f :: Tree a -> b f t = case t of
Leaf -> ...
Branch l k r -> ... (f l) k (f r) dieses Schema ist eine Funktion h ¨oherer Ordnung:
fold :: ( ... ) -> ( ... ) -> ( Tree a -> b ) fold leaf branch = \ t -> case t of
Leaf -> leaf Branch l k r ->
branch (fold leaf branch l) k (fold leaf branch r)
summe = fold 0 ( \ l k r -> l + k + r )
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 76 / 209
Rekursionsmuster
Rekursion ¨uber Listen
and :: List Bool -> Bool and xs = case xs of
Nil -> True ; Cons x xs’ -> x && and xs’
length :: List a -> N length xs = case xs of
Nil -> Z ; Cons x xs’ -> S (length xs’) fold :: b -> ( a -> b -> b ) -> List a -> b fold nil cons xs = case xs of
Nil -> nil
Cons x xs’ -> cons x ( fold nil cons xs’ ) and = fold True (&&)
length = fold Z ( \ x y -> S y)
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 77 / 209
Rekursionsmuster
Rekursionsmuster (Prinzip)
ein Rekursionsmuster anwenden = jeden
Konstruktor durch eine passende Funktion ersetzen.
data List a = Nil | Cons a (List a)
fold ( nil :: b ) ( cons :: a -> b -> b ) :: List a -> b
Rekursionsmuster instantiieren =
(Konstruktor-)Symbole interpretieren (durch Funktionen) = eine Algebra angeben.
length = fold Z ( \ _ l -> S l ) reverse = fold Nil ( \ x ys -> )
Johannes Waldmann, HTWK Leipzig Deklarative (= fortgeschrittene) Programmierung Vorlesung WS 09,10; SS 12–14, 1613. Juli 2016 78 / 209