• Keine Ergebnisse gefunden

Formen der deklarativen Programmierung

N/A
N/A
Protected

Academic year: 2022

Aktie "Formen der deklarativen Programmierung"

Copied!
30
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Deklarative (= fortgeschrittene)

Programmierung Vorlesung

WS 09,10; SS 12–14, 16

Johannes Waldmann, HTWK Leipzig 13. Juli 2016

– Typeset by FoilTEX

Einleitung

Formen der deklarativen Programmierung

•funktionale Programmierung:foldr (+) 0 [1,2,3]

foldr f z l = case l of

[] -> z ; (x:xs) -> f x (foldr f z xs)

•logische Programmierung:append(A,B,[1,2,3]).

append([],YS,YS).

append([X|XS],YS,[X|ZS]):-append(XS,YS,ZS).

•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))

– Typeset by FoilTEX 1

Definition

deklarativ: jedes (Teil-)Programm/Ausdruck hat einenWert (. . . und keine weitere (versteckte)Wirkung).

Werte k¨onnen sein:

•“klassische” Daten (Zahlen, Listen, B¨aume. . . )

•Funktionen (Sinus, . . . )

•Aktionen (Datei schreiben, . . . )

– Typeset by FoilTEX 2

Softwaretechnische Vorteile

. . . der deklarativen Programmierung

•Beweisbarkeit: Rechnen mit Programmen wie in der Mathematik mit Termen

•Sicherheit: es gibt keine Nebenwirkungen und Wirkungen sieht man bereits am Typ

•Wiederverwendbarkeit: durch Entwurfsmuster (=

Funktionen h¨oherer Ordnung)

•Effizienz: durch Programmtransformationen im Compiler,

•Parallelisierbarkeit: durch Nebenwirkungsfreiheit

– Typeset by FoilTEX 3

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)

– Typeset by FoilTEX 4

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 nachx.

•Induktionsanfang:x == []. . .

•Induktionsschritt:x == h : t. . .

– Typeset by FoilTEX 5

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 durchAnnotationen:

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

– Typeset by Foil 6

Beispiel Parallelisierung (C#, PLINQ)

•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;}

2X26−1 x=0

f(x) Enumerable.Range(0,1<<26).Select(f).Sum()

•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 PLINQhttps://msdn.microsoft.

com/en-us/library/dd997425(v=vs.110).aspx

– Typeset by Foil 7

(2)

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

– Typeset by FoilTEX 8

Deklarative Programmierung in der Lehre

•funktionale Programmierung: diese Vorlesung

•logische Programmierung: inAngew. K¨unstl. Intell.

•Constraint-Programmierung: als Master-Wahlfach Beziehungen zu weiteren LV: Voraussetzungen

•B¨aume, Terme (Alg.+DS, Grundlagen Theor. Inf.)

•Logik (Grundlagen TI, Softwaretechnik) Anwendungen:

•Softwarepraktikum

•weitere Sprachkonzepte inPrinzipien v.

Programmiersprachen

•Programmverifikation(vorw. f. imperative Programme)

– Typeset by FoilTEX 9

Konzepte und Sprachen

Funktionale Programmierung ist einKonzept.

Realisierungen:

•in prozeduralen Sprachen:

Unterprogramme als Argumente (in Pascal) Funktionszeiger (in C)

•in OO-Sprachen: Befehlsobjekte

•Multi-Paradigmen-Sprachen:

Lambda-Ausdr¨ucke in C#, Scala, Clojure

•funktionale Programmiersprachen (LISP, ML, Haskell) Die Erkenntnisse sind sprachunabh¨angig.

•A good programmer can write LISP in any language.

•Learn Haskell and become a better Java programmer.

– Typeset by FoilTEX 10

Gliederung der Vorlesung

•Terme, Termersetzungssysteme algebraische Datentypen, Pattern Matching, Persistenz

•Funktionen (polymorph, h¨oherer Ordnung), Lambda-Kalk¨ul, Rekursionsmuster

•Typklassen zur Steuerung der Polymorphie

•Bedarfsauswertung, unendl. Datenstrukturen (Iterator-Muster)

•weitere Entwurfsmuster

•Code-Qualit¨at, Code-Smells, Refactoring

– Typeset by FoilTEX 11

Softwaretechnische Aspekte

algebraische Datentypen, Pattern Matching, Termersetzungssysteme

Scale: case class, Java: Entwurfsmuster Kompositum, immutable objects, das Datenmodell von Git

Funktionen (h¨oherer Ordnung), Lambda-Kalk¨ul, Rekursionsmuster

Lambda-Ausdr¨ucke in C#, Entwurfsmuster Besucher Codequalit¨at, code smells, Refaktorisierung

Typklassen zur Steuerung der Polymorphie

Interfaces in Java/C# , automatische Testfallgenerierung

Bedarfsauswertung, unendl. Datenstrukturen

Iteratoren, Str¨ome, LINQ

– Typeset by FoilTEX 12

Organisation der LV

•jede Woche eine Vorlesung, eine ¨Ubung

•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

•Pr¨ufungszulassung: regelm¨aßiges (d.h. innerhalb der jeweiligen Deadline) und erfolgreiches (ingesamt≥50%

der Pflichtaufgaben) Bearbeiten von ¨Ubungsaufgaben.

•Pr¨ufung: Klausur (ohne Hilfsmittel)

– Typeset by FoilTEX 13

Literatur

•Skripte:

aktuelles Semesterhttp:

//www.imn.htwk-leipzig.de/˜waldmann/lehre.html vorige Semesterhttp://www.imn.htwk-leipzig.de/

˜waldmann/lehre-alt.html

•Entwurfsmuster:http://www.imn.htwk-leipzig.

de/˜waldmann/draft/pub/hal4/emu/

•Maurice Naftalin und Phil Wadler:Java Generics and Collections, O’Reilly 2006

•http://haskell.org/(Sprache, Werkzeuge, Tutorials),http://book.realworldhaskell.org/

– Typeset by Foil 14

¨Ubungen

•im Pool Z430, vgl.http://www.imn.htwk-leipzig.

de/˜waldmann/etc/pool/

•Beispiele f. deklarative Programmierung funktional: Haskell mit ghci,

logisch: Prolog mit swipl, constraint: mit mathsat, z3

•Haskell-Entwicklungswerkzeuge

(eclipsefp, leksah, . . . ,http://xkcd.org/378/) API-Suchmaschinehttp://www.haskell.org/hoogle/

•Commercial Uses of Functional Programming

http://www.syslog.cl.cam.ac.uk/2013/09/22/

liveblogging-cufp-2013/

– Typeset by Foil 15

(3)

Daten

Wiederholung: Terme

•(Pr¨adikatenlogik)Signatur Σist Menge von Funktionssymbolen mit Stelligkeiten ein Termtin SignaturΣist

Funktionssymbolf∈Σder Stelligkeitk

mit Argumenten(t1, . . . , tk), die selbst Terme sind.

Term(Σ) =Menge der Terme ¨uber SignaturΣ

•(Graphentheorie) ein Term ist ein gerichteter, geordneter, markierter Baum

•(Datenstrukturen)

Funktionssymbol=Konstruktor, Term=Baum

– Typeset by FoilTEX 16

Beispiele: Signatur, Terme

•Signatur:Σ1={Z/0, S/1, f /2}

•Elemente vonTerm(Σ1):

Z(), S(S(Z())), f(S(S(Z())), Z())

•Signatur:Σ2={E/0, A/1, B/1}

•Elemente vonTerm(Σ2): . . .

– Typeset by FoilTEX 17

Algebraische Datentypen

data Foo = Foo { bar :: Int, baz :: String } deriving Show

Bezeichnungen (benannte Notation)

•data Fooist Typname

•Foo { .. }ist Konstruktor

•bar, bazsind Komponenten x :: Foo

x = Foo { bar = 3, baz = "hal" } Bezeichnungen (positionelle Notation) data Foo = Foo Int String y = Foo 3 "bar"

– Typeset by FoilTEX 18

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

– Typeset by FoilTEX 19

Mehrsortige Signaturen

•(bisher) einsortige Signatur

Abbildung von Funktionssymbol nach Stelligkeit

•(neu) mehrsortige Signatur

Menge von SortensymbolenS={S1, . . .} Abb. von F.-Symbol nach Typ

Typist Element ausS×S

Folge der Argument-Sorten, Resultat-Sorte Bsp.:S={Z, B},Σ ={07→([], Z), p7→([Z, Z], Z), e7→([Z, Z], B), a7→([B, B], B)}.

•Term(Σ): konkrete Beispiele, allgemeine Definition?

– Typeset by FoilTEX 20

Rekursive Datentypen

data Tree = Leaf {}

| Branch { left :: Tree , right :: Tree }

¨Ubung: Objekte dieses Typs erzeugen

(benannte und positionelle Notation der Konstruktoren)

– Typeset by FoilTEX 21

Daten mit Baum-Struktur

•mathematisches Modell: Term ¨uber Signatur

•programmiersprachliche Bezeichnung:algebraischer Datentyp(die Konstruktoren bilden eine Algebra)

•praktische Anwendungen:

Formel-B¨aume (in Aussagen- und Pr¨adikatenlogik) Suchb¨aume (in VL Algorithmen und Datenstrukturen, in

java.util.TreeSet<E>) DOM (Document Object Model)

https://www.w3.org/DOM/DOMTR

JSON (Javascript Object Notation) z.B. f¨ur AJAX http://www.ecma-international.org/

publications/standards/Ecma-404.htm

– Typeset by Foil 22

Bezeichnungen f ¨ur Teilterme

•Position: Folge von nat¨urlichen Zahlen

(bezeichnet einen Pfad von der Wurzel zu einem Knoten) Beispiel: f¨urt=S(f(S(S(Z())), Z()))

ist[0,1]eine Position int.

•Pos(t) =die Menge der Positionen eines Termst Definition: wennt=f(t1, . . . , tk),

dannPos(t) ={[]} ∪ {[i−1]++p|1≤i≤k∧p∈Pos(ti)}. dabei bezeichnen:

•[]die leere Folge,

•[i]die Folge der L¨ange 1 mit Elementi,

•++den Verkettungsoperator f¨ur Folgen

– Typeset by Foil 23

(4)

Operationen mit (Teil)Termen

•t[p] =der Teilterm vontan Positionp Beispiel:S(f(S(S(Z())), Z()))[0,1] =. . .

Definition (durch Induktion ¨uber die L¨ange vonp): . . .

•t[p:=s]: wiet, aber mit Termsan Positionp Beispiel:S(f(S(S(Z())), Z()))[[0,1] :=S(Z)]x=. . . Definition (durch Induktion ¨uber die L¨ange vonp): . . .

– Typeset by FoilTEX 24

Operationen mit Variablen in Termen

•Term(Σ, V) =Menge der Terme ¨uber SignaturΣmit Variablen ausV

Beispiel:Σ ={Z/0, S/1, f /2}, V ={y}, f(Z(), y)∈Term(Σ, V).

•Substitutionσ: partielle AbbildungV →Term(Σ) Beispiel:σ1={(y, S(Z()))}

•eine Substitution auf einen Term anwenden:tσ:

Intuition: wiet, aber stattvimmerσ(v) Beispiel:f(Z(), y)σ1=f(Z(), S(Z())) Definition durch Induktion ¨ubert

– Typeset by FoilTEX 25

Termersetzungssysteme

•Daten=Terme (ohne Variablen)

•ProgrammR=Menge von Regeln

Bsp:R={(f(Z(), y), y), (f(S(x), y), S(f(x, y)))}

•Regel=Paar(l, r)von Termen mit Variablen

•Relation→Rist Menge aller Paare(t, t0)mit es existiert(l, r)∈R

es existiert Positionpint

es existiert Substitutionσ: (Var(l)∪Var(r))→Term(Σ) so daßt[p] =lσundt0=t[p:=rσ].

– Typeset by FoilTEX 26

Termersetzungssysteme als Programme

• →RbeschreibteinenSchritt der Rechnung vonR,

•transitive und reflexive H¨ulle→R

beschreibtFolgevon Schritten.

•Resultateiner Rechnung ist Term inR-Normalform (:=ohne→R-Nachfolger)

dieses Berechnungsmodell ist im allgemeinen

•nichtdeterministischR1={C(x, y)→x, C(x, y)→y} (ein Term kann mehrere→R-Nachfolger haben, ein Term kann mehrere Normalformen erreichen)

•nicht terminierendR2={p(x, y)→p(y, x)} (es gibt eine unendliche Folge von→R-Schritten, es kann Terme ohne Normalform geben)

– Typeset by FoilTEX 27

Konstruktor-Systeme

F¨ur TRSR ¨uber SignaturΣ: Symbols∈Σheißt

•definiert, wenn∃(l, r)∈R:l[] =s(. . .) (das Symbol in der Wurzel ists)

•sonstKonstruktor.

Das TRSRheißtKonstruktor-TRS, falls:

•definierte Symbole kommen linksnur 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.

– Typeset by FoilTEX 28

¨Ubung Terme, TRS

•Geben Sie die Signatur des Terms√

a·a+b·ban.

•Geben Sie ein Elementt∈Term({f /1, g/3, c/0})an mit t[1] =c().

mitghci:

•data T = F T | G T T T | C deriving Show erzeugen Sie o.g. Terme (durch Konstruktoraufrufe) DieGr¨oßeeines Termstist definiert durch

|f(t1, . . . , tk)|= 1 +Pk i=1|ti|.

•Bestimmen Sie|√

a·a+b·b|.

•Beweisen Sie∀Σ :∀t∈Term(Σ) :|t|=|Pos(t)|.

– Typeset by FoilTEX 29

Vervollst¨andigen Sie die Definition derTiefevon Termen:

depth(f()) = 0

k >0 ⇒ depth(f(t1, . . . , tk)) =. . .

•Bestimmen Siedepth(√

a·a+b·b)

•Beweisen Sie∀Σ :∀t∈Term(Σ) : depth(t)<|t|. F¨ur die SignaturΣ ={Z/0, S/1, f /2}:

•f¨ur welche Substitutionσgiltf(x, Z)σ=f(S(Z), Z)?

•f¨ur diesesσ: bestimmen Sief(x, S(x))σ.

Notation f¨ur Termersetzungsregeln: anstatt(l, r)schreibe l→r.

– Typeset by Foil 30

Abk¨urzung f¨ur Anwendung von 0-stelligen Symbolen:

anstattZ()schreibeZ.

•F¨urR={f(S(x), y)→f(x, S(y)), f(Z, y)→y} bestimme alleR-Normalformen vonf(S(Z), S(Z)).

•f¨urRd=R∪ {d(x)→f(x, x)}

bestimme alleRd-Normalformen vond(d(S(Z))).

•Bestimme die SignaturΣdvonRd.

Bestimme die Menge der Terme ausTerm(Σd), die Rd-Normalformen sind.

•f¨ur die Signatur{A/2, D/0}:

definiere Termet0=D, ti+1=A(ti, D).

– Typeset by Foil 31

(5)

Zeichnet3. Bestimme|ti|.

•f¨urS={A(A(D, x), y)→A(x, A(x, y))}

bestimmeS-Normalform(en), soweit existieren, der Termet2, t3, t4. Zusatz: vontiallgemein.

Abk¨urzung f¨ur mehrfache Anwendung eines einstelligen Symbols:A(A(A(A(x)))) =A4(x)

•f¨ur{A(B(x))→B(A(x))}

¨uber Signatur{A/1, B/1, E/0}: bestimme Normalform vonAk(Bk(E)) f¨urk= 1,2,3,allgemein.

•f¨ur{A(B(x))→B(B(A(x)))}

– Typeset by FoilTEX 32

¨uber Signatur{A/1, B/1, E/0}: bestimme Normalform vonAk(B(E)) f¨urk= 1,2,3,allgemein.

– Typeset by FoilTEX 33

Programme

Funktionale Programme

. . . sind spezielle Term-Ersetzungssysteme. Beispiel:

Signatur:Seinstellig,Znullstellig,fzweistellig.

Ersetzungssystem{f(Z, y)→y, f(S(x0), y)→S(f(x0, y))}. Starttermf(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)

– Typeset by FoilTEX 34

Pattern Matching

data Tree = Leaf | Branch Tree Tree size :: Tree -> Int

size t = case t of { ... ; Branch l r -> ... }

•Syntax allgemein:

case t of { <Muster> -> <Ausdruck> ; ... }

•<Muster>enth¨alt Konstruktoren und Variablen, entspricht linker Seite einer Term-Ersetzungs-Regel,

<Ausdruck>entspricht rechter Seite

•Def.:tpaßtzum Musterl: es existiertσmitlσ=t

•dynamische Semantik: f¨ur das erste passende Muster wirdrσausgewertet

•statische Semantik: jedes<Muster>hat gleichen Typ wiet, alle<Ausdruck>haben ¨ubereinstimmenden Typ.

– Typeset by FoilTEX 35

Eigenschaften von Case-Ausdr ¨ucken

eincase-Ausdruck heißt

•disjunkt, wenn die Muster nicht ¨uberlappen

(es gibt keinen Term, der zu mehr als 1 Muster paßt)

•vollst¨andig, wenn die Muster den gesamten Datentyp abdecken

(es gibt keinen Term, der zu keinem Muster paßt) Bespiele (f¨urdata 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 -> .. }

– Typeset by FoilTEX 36

data

und

case

typisches Vorgehen beim Verarbeiten algebraischer Daten vom TypT:

•F¨ur jeden Konstruktor des Datentyps data T = C1 ...

| C2 ...

•schreibe einen Zweig in der Fallunterscheidung f x = case x of

C1 ... -> ...

C2 ... -> ...

•Argumente der Konstruktoren sind Variablen⇒ Case-Ausdruck ist disjunkt und vollst¨andig.

– Typeset by FoilTEX 37

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:

•implementiere Multiplikation, Potenz

•beweise die ¨ublichen Eigenschaften (Addition, Multiplikation sind assoziativ, kommutativ, besitzen neutrales Element)

– Typeset by Foil 38

Pattern Matching in versch. Sprachen

•Scala: case classeshttp://docs.scala-lang.org/

tutorials/tour/case-classes.html

•C# (7):https:

//github.com/dotnet/roslyn/blob/features/

patterns/docs/features/patterns.md

•Javascript?

Nicht verwechseln mitregular expression matchingzur String-Verarbeitung. Es geht um algebraische (d.h.

baum-artige) Daten!

– Typeset by Foil 39

(6)

¨Ubung Pattern Matching, Programme

•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:

syntaktisch korrekt?

statisch korrekt?

Resultat (dynamische Semantik) disjunkt? vollst¨andig?

1. case False of { True -> C } 2. case False of { C -> True }

– Typeset by FoilTEX 40

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 }

•Operationen auf Wahrheitswerten:

import qualified Prelude

data Bool = False | True deriving Prelude.Show not :: Bool -> Bool -- Negation

not x = case x of ... -> ...

– Typeset by FoilTEX 41

... -> ...

Syntax: wenn nachofkein{folgt:

implizite{ ; }durchAbseitsregel (layout rule).

•(&&) :: Bool -> Bool -> Bool x && y = case ... of ...

Syntax: Funktionsname

beginnt mit Buchstabe: steht vor Argumenten, beginnt mit Zeichen: zwischen Argumenten (als

Operator)

Operator als Funktion:(&&) False True, Funktion als Operator:True ‘f‘ False.

•Listen von Wahrheitswerten:

– Typeset by FoilTEX 42

data List = Nil | Cons Bool List deriving Prelude.Show and :: List -> Bool

and l = case l of ...

entsprechendor :: List -> Bool

•(Wdhlg.) welche Signatur beschreibt bin¨are B¨aume (jeder Knoten hat 2 oder 0 Kinder, die B¨aume sind; es gibt keine Schl¨ussel)

•geben Sie die dazu ¨aquivalentedata-Deklaration an:

data T = ...

•implementieren Sie daf¨ur die Funktionen size :: T -> Prelude.Int

– Typeset by FoilTEX 43

depth :: T -> Prelude.Int benutzePrelude.+(das ist Operator), Prelude.min, Prelude.max

•f¨ur Peano-Zahlendata N = Z | S N implementieren Sieplus, mal, min, max

– Typeset by FoilTEX 44

Polymorphie

Definition, Motivation

•Beispiel: bin¨are B¨aume mit Schl¨ussel vom Type data Tree e = Leaf

| Branch (Tree e) e (Tree e) Branch Leaf True Leaf :: Tree Bool

Branch Leaf 42 Leaf :: Tree Int

•Definition:

ein polymorpher Datentyp ist einTypkonstruktor (=eine Funktion, die Typen auf einen Typ abbildet)

•unterscheide:Treeist der Typkonstruktor,Branchist ein Datenkonstruktor

– Typeset by FoilTEX 45

Beispiele f. Typkonstruktoren (I)

•Kreuzprodukt:

data Pair a b = Pair a b

•disjunkte Vereinigung:

data Either a b = Left a | Right b

•data Maybe a = Nothing | Just a

•Haskell-Notation f¨ur Produkte:

(1,True)::(Int,Bool) f¨ur0,2,3, . . . Komponenten

– Typeset by Foil 46

Beispiele f. Typkonstruktoren (II)

•bin¨are B¨aume

data Bin a = Leaf

| Branch (Bin a) a (Bin a)

•Listen

data List a = Nil

| Cons a (List a)

•B¨aume

data Tree a = Node a (List (Tree a))

– Typeset by Foil 47

(7)

Polymorphe Funktionen

Beispiele:

•Spiegeln einer Liste:

reverse :: forall e . List e -> List e

•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.

– Typeset by FoilTEX 48

Bezeichnungen f. Polymorphie

data List e = Nil | Cons e (List e)

•Listist einTypkonstruktor

•List eist einpolymorpherTyp (ein Typ-Ausdruck mitTyp-Variablen)

•List Boolist einmonomorpher Typ

(entsteht durchInstantiierung: Substitution der Typ-Variablen durch Typen)

•polymorphe Funktion:

reverse:: forall e . List e -> List e monomorphe Funktion:xor:: List Bool -> Bool polymorphe Konstante:Nil::forall e. List e

– Typeset by FoilTEX 49

Operationen auf Listen (I)

data List a = Nil | Cons a (List a)

•append xs ys = case xs of Nil ->

Cons x xs’ ->

• ¨Ubung: formuliere und beweise:appendist assoziativ.

•reverse xs = case xs of Nil ->

Cons x xs’ ->

•beweise:

forall xs . reverse (reverse xs) == xs

– Typeset by FoilTEX 50

Operationen auf Listen (II)

Die vorige Implementierung vonreverseist (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 vonrev_appableiten rev_app xs ys = case xs of ...

– Typeset by FoilTEX 51

Operationen auf B¨aumen

data List e = Nil | Cons e (List e)

data Bin e = Leaf | Branch (Bin e) e (Bin e) Knotenreihenfolgen

•preorder :: forall e . Bin e -> List e preorder t = case t of ...

•entsprechendinorder,postorder

•und Rekonstruktionsaufgaben

Adressierug von Knoten (False=links,True=rechts)

•get :: Tree e -> List Bool -> Maybe e

•positions :: Tree e -> List (List Bool)

– Typeset by FoilTEX 52

¨Ubung Polymorphie

Geben Sie alle Elemente dieser Datentypen an:

•Maybe ()

•Maybe (Bool, Maybe ())

•Either (Bool,Bool) (Maybe (Maybe Bool)) Operationen auf Listen:

•append, reverse, rev app Operationen auf B¨aumen:

•preorder, inorder, postorder, (Rekonstruktion)

•get, (positions)

– Typeset by FoilTEX 53

Kochrezept: Objektkonstruktion

Aufgabe (Bsp):

x :: Either (Maybe ()) (Pair Bool ()) L¨osung (Bsp):

•der TypEither a bhat Konstruktoren Left a | Right b. W¨ahleRight b.

Die Substitution f¨ur die Typvariablen ist a = Maybe (), b = Pair Bool ().

x = Right ymity :: Pair Bool ()

•der TypPair a bhat KonstruktorPair a b.

die Substitution f¨ur diese Typvariablen ist a = Bool, b = ().

– Typeset by Foil 54

y = Pair p qmitp :: Bool, q :: ()

•der TypBoolhat KonstruktorenFalse | True, w¨ahle p = False. der Typ()hat Konstruktor(), alsoq=() Insgesamtx = Right y = Right (Pair False ()) Vorgehen (allgemein)

•bestimme den Typkonstruktor

•bestimme die Substitution f¨ur die Typvariablen

•w¨ahle einen Datenkonstruktor

•bestimme Anzahl und Typ seiner Argumente

•w¨ahle Werte f¨ur diese Argumente nach diesem Vorgehen.

– Typeset by Foil 55

(8)

Kochrezept: Typ-Bestimmung

Aufgabe (Bsp.) bestimme Typ vonx(erstes Arg. vonget):

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:

•bestimme das Muster, durch welchesxdeklariert wird.

L¨osung:Cons x p’ ->

•bestimme den Typ diese Musters

– Typeset by FoilTEX 56

L¨osung: ist gleich dem Typ der zugeh¨origen Diskriminantep

•bestimme das Muster, durch daspdeklariert wird L¨osung:at p t =

•bestimme den Typ vonp

L¨osung: durch Vergleich mit Typdeklaration vonat(pist das erste Argument)p :: Position, also

Cons x p’ :: Position = List N, alsox :: N.

Vorgehen zur Typbestimmung eines Namens:

•finde die Deklaration (Muster einer Fallunterscheidung oder einer Funktionsdefinition)

•bestimme den Typ des Musters (Fallunterscheidung: Typ der Diskriminante, Funktion: deklarierter Typ)

– Typeset by FoilTEX 57

Statische Typisierung und Polymorphie

Def: dynamische Typisierung:

•die Daten (zur Laufzeit des Programms, im Hauptspeicher) haben einen Typ

Def: statische Typisierung:

•Bezeichner, Ausdr¨ucke (im Quelltext) haben einen Type (zur ¨Ubersetzungszeit bestimmt).

•f¨urjedeAusf¨uhrung des Programms gilt: der statische Typ eines Ausdrucks ist gleich dem dynamischen Typ seines Wertes

– Typeset by FoilTEX 58

Bsp. f¨ur Programm ohne statischen Typ (Javascript) function f (x) {

if (x>0) { return function () { return 42; } } else { return "foobar"; } }

Dann: Auswertung vonf(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"

– Typeset by FoilTEX 59

Nutzen der statischen Typisierung:

•beim Programmieren: Entwurfsfehler werden zu Typfehlern, diese werden zur Entwurfszeit automatisch erkannt⇒fr¨uher erkannte Fehler lassen sich leichter beheben

•beim Ausf¨uhren: es gibt keine Lauzeit-Typfehler⇒keine Typpr¨ufung zur Laufzeit n¨otig, effiziente Ausf¨uhrung Nutzen der Polymorphie:

•Flexibilit¨at, nachnutzbarer Code, z.B. Anwender einer Collection-Bibliothek legt Element-Typ fest (Entwickler der Bibliothek kennt den Element-Typ nicht)

•gleichzeitig bleibt statische Typsicherheit erhalten

– Typeset by FoilTEX 60

Von der Spezifikation zur Implementierung (I)

Bsp: Addition von Peano-Zahlendata 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.

– Typeset by FoilTEX 61

Von der Spezifikation zur Implementierung (II)

Bsp: homogene Listen

data List a = Nil | Cons a (List a) Aufgabe: implementieremaximum :: List N -> N Spezifikation:

maximum (Cons x1 Nil) = x1

maximum (append xs ys) = max (maximum xs) (maximum ys)

•substitutierexs = Nil, erhalte

maximum (append Nil ys) = maximum ys

= max (maximum Nil) (maximum ys)

d.h.maximum Nilsollte das neutrale Element f¨urmax (auf nat¨urlichen Zahlen) sein, also0(geschriebenZ).

– Typeset by Foil 62

•substitutierexs = 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¨urmin, minimumfunktioniert das nicht so, denn minhat f¨urNkein neutrales Element.

– Typeset by Foil 63

(9)

Unver¨anderliche Objekte

¨Uberblick

•alle Attribute aller Objekte sind unver¨anderlich (final)

•anstatt Objekt zu ¨andern, konstruiert man ein neues Eigenschaften des Programmierstils:

•vereinfacht Formulierung und Beweis von Objekteigenschaften

•parallelisierbar (keine updates, keinedata races) http://fpcomplete.com/

the-downfall-of-imperative-programming/

•Persistenz (Verf¨ugbarkeit fr¨uherer Versionen)

•Belastung des Garbage Collectors (. . . daf¨ur ist er da)

– Typeset by FoilTEX 64

Beispiel: Einf ¨ugen in Baum

•destruktiv:

interface Tree<K> { void insert (K key); } Tree<String> t = ... ;

t.insert ("foo");

•persistent (Java):

interface Tree<K> { Tree<K> insert (K key); } Tree<String> t = ... ;

Tree<String> u = t.insert ("foo");

•persistent (Haskell):

insert :: Tree k -> k -> Tree k

– Typeset by FoilTEX 65

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:

•Ord kentsprichtK implements Comparable<K>, genaueres sp¨ater (Haskell-Typklassen)

•wie teuer ist die Persistenz?

(wieviel M¨ull entsteht bei eineminsert?)

– Typeset by FoilTEX 66

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 )

– Typeset by FoilTEX 67

Persistente Objekte in Git

http://git-scm.com/

•Distributed development.

•Strong support fornon-lineardevelopment.

(Branching and merging are fast and easy.)

•Efficient handling oflargeprojects.

(z. B. Linux-Kernel,http://kernel.org/)

•Toolkit design.

•Cryptographic authentication of history.

– Typeset by FoilTEX 68

Objekt-Versionierung in Git

•Objekt-Typen:

Datei (blob),

Verzeichnis (tree), mit Verweisen auf blobs und trees Commit, mit Verweisen auf tree u. commits (Vorg¨anger)

git cat-file -p <hash>

•Objekte sindunver¨anderlichund durch SHA1-Hash (160 bit=40 Hex-Zeichen) identifiziert

•statt ¨Uberschreiben: neue Objekte anlegen

•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

– Typeset by FoilTEX 69

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 inAfreie Variable durch ein Lambda inBgebunden wird.

– Typeset by Foil 70

Der Lambda-Kalk ¨ul

. . . als weiteres Berechnungsmodell,

(vgl. Termersetzungssysteme, Turingmaschine, Random-Access-Maschine)

Syntax: die Menge der Lambda-TermeΛist

•jede Variable ist ein Term:v∈V ⇒v∈Λ

•Funktionsanwendung (Applikation):

F ∈Λ, A∈Λ⇒(F A)∈Λ

•Funktionsdefinition (Abstraktion):

v∈V, B∈Λ⇒(λv.B)∈Λ Semantik: eine Relation→βaufΛ (vgl.→Rf¨ur TermersetzungssystemR)

– Typeset by Foil 71

(10)

Freie und gebundene Variablen(vorkommen)

•Das Vorkommen vonv∈V an Positionpin Termtheißt frei, wenn ”dar¨uber keinλv. . . . steht“

•Def.fvar(t) =Menge der intfrei vorkommenden Variablen (definiere durch strukturelle Induktion)

•Eine Variablexheißt inAgebunden, fallsAeinen Teilausdruckλx.Benth¨alt.

•Def.bvar(t) =Menge der intgebundenen Variablen Bsp:fvar(x(λx.λy.x)) ={x},bvar(x(λx.λy.x)) ={x, y},

– Typeset by FoilTEX 72

Semantik des Lambda-Kalk ¨uls: Reduktion

β

Relation→βaufΛ(ein Reduktionsschritt) Es giltt→βt0, falls

• ∃p∈Pos(t), so daß

•t[p] = (λx.B)Amitbvar(B)∩fvar(A) =∅

•t0=t[p:=B[x:=A]]

dabei bezeichnetB[x:=A]ein Kopie vonB, bei der jedes freie Vorkommen vonxdurchAersetzt ist Ein (Teil-)Ausdruck der Form(λx.B)AheißtRedex.

(Dort kann weitergerechnet werden.) Ein Term ohne Redex heißtNormalform.

(Normalformen sind Resultate von Rechnungen.)

– Typeset by FoilTEX 73

Semantik . . . : gebundene Umbenennung

α

•Relation→αaufΛ, beschreibtgebundene Umbenennung einer lokalen Variablen.

•Beispielλx.f xz→αλy.f yz.

(fundzsind frei, k¨onnen nicht umbenannt werden)

•Definitiont→αt0:

∃p∈Pos(t), so daßt[p] = (λx.B) y /∈bvar(B)∪fvar(B)

t0=t[p:=λy.B[x:=y]]

•wird angewendet, umbvar(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

– Typeset by FoilTEX 74

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

Darff(8)ersetzt werden durchf[y:= 8]? - Nein:

int x = 3;

int g(int x) { return (x + (x+8)); } // g(5) => 18

Das freiexin(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

– Typeset by FoilTEX 75

Lambda-Terme: verk ¨urzte Notation

•Applikation ist links-assoziativ, Klammern weglassen:

(. . .((F A1)A2). . . An)∼F A1A2. . . An

Beispiel:((xz)(yz))∼xz(yz) Wirkt auch hinter dem Punkt:

(λx.xx)bedeutet(λx.(xx))— und nicht((λx.x)x)

•geschachtelte Abstraktionen unter ein Lambda schreiben:

(λx1.(λx2. . . .(λxn.B). . .))∼λx1x2. . . xn.B Beispiel:λx.λy.λz.B∼λxyz.B

– Typeset by FoilTEX 76

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:

gegebent = \ f x -> f (f x) bestimmet succ 0, t t succ 0, t t t succ 0, t t t t succ 0, ...

– Typeset by FoilTEX 77

Typen

f¨ur nicht polymorphe Typen: tats¨achlicher Argumenttyp muß mit deklariertem Argumenttyp ¨ubereinstimmen:

wennf::A→Bundx::A, dann(f x) ::B.

bei polymorphen Typen k¨onnen der Typ vonf ::A→B und der Typ vonx::A0Typvariablen enthalten.

Beispiel:λx.x::∀t.t→t.

Dann m¨ussenAundA0nicht ¨ubereinstimmen, sondern nur unifizierbar sein (eine gemeinsame Instanz besitzen).

Beispiel:(λx.x)True

benutze Typ-Substitutionσ={(t,Bool)}.

Bestimme allgemeinsten Typ vont=λf x.f(f x)), von(tt).

– Typeset by Foil 78

Beispiel f ¨ur Typ-Bestimmung

Aufgabe: bestimme den allgemeinsten Typ vonλf x.f(f x)

•Ansatz mit Typvariablenf::t1, x::t2

•betrachte(f x): der Typ vonfmuß ein Funktionstyp sein, alsot1= (t11→t12)mit neuen Variablent11, t12.

Dann giltt11=t2und(f x) ::t12.

•betrachtef(f x). Wir habenf::t11→t12und(f x) ::t12, also folgtt11=t12. Dannf(f x) ::t12.

•betrachteλx.f(f x).

Ausx::t12undf(f x) ::t12folgtλx.f(f x) ::t12→t12.

•betrachteλf.(λx.f(f x)).

Ausf ::t12→t12undλx.f(f x) ::t12→t12

folgtλf x.f(f x) :: (t12→t12)→(t12→t12)

– Typeset by Foil 79

(11)

Verk ¨urzte Notation f ¨ur Typen

•Der Typ-Pfeil istrechts-assoziativ:

T1→T2→ · · · →Tn→T bedeutet (T1→(T2→ · · · →(Tn→T)· · ·))

•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¨urzungT1→T2→T.

– Typeset by FoilTEX 80

Lambda-Ausdr ¨ucke in C#

•Beispiel (Fkt. 1. Ordnung)

Func<int,int> f = (int x) => x*x;

f (7);

• ¨Ubung (Fkt. 2. Ordnung) — erg¨anze alle Typen:

??? t = (??? g) => (??? x) => g (g (x));

t (f)(3);

•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);

• ¨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);

– Typeset by FoilTEX 81

Lambda-Ausdr ¨ucke in Java(8)

funktionalesInterface (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"); }

– Typeset by FoilTEX 82

Lambda-Ausdr ¨ucke in Javascript

$ node

> var f = function (x){return x+3;}

undefined

> f(4) 7

– Typeset by FoilTEX 83

Beispiele Fkt. h ¨oherer Ord.

•Haskell-Notation f¨ur Listen:

data List a = Nil | Cons a (List a) data [a] = [] | a : [a]

•Verarbeitung von Listen:

filter :: (a -> Bool) -> [a] -> [a]

takeWhile :: (a -> Bool) -> [a] -> [a]

partition :: (a -> Bool) -> [a] -> ([a],[a])

•Vergleichen, Ordnen:

nubBy :: (a -> a -> Bool) -> [a] -> [a]

data Ordering = LT | EQ | GT minimumBy

:: (a -> a -> Ordering) -> [a] -> a

– Typeset by FoilTEX 84

¨Ubung Lambda-Kalk¨ul

•Wiederholung: konkrete Syntax, abstrakte Syntax, Semantik

•S=λxyz.xz(yz), K =λab.a, Normalform vonSKKc

•(mitdata N=Z|S N) bestimme Normalform vonttSZ f¨urt=λf x.f(f x),

•definiereΛals algebraischen Datentypdata L = ...

(3 Konstruktoren)

implementieresize :: L -> Int, depth :: L -> Int.

implementierebvar :: L -> S.Set String,

– Typeset by FoilTEX 85

fvar :: L -> S.Set String,

siehe Folie mit Definitionen und dort angegebene Testf¨alle

benutzeimport qualified Data.Set as S, API-Dokumentation:https://hackage.haskell.

org/package/containers/docs/Data-Set.html

•autotool-Aufgaben Lambda-Kalk¨ul

– Typeset by Foil 86

¨Ubung Fkt. h¨oherer Ordnung

•Typisierung, Beispiele in Haskell, C#, Java, Javascript compose ::

compose = \ f g -> \ x -> f (g x)

•Implementierung von takeWhile, dropWhile

– Typeset by Foil 87

(12)

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))

– Typeset by FoilTEX 88

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 Schemaisteine 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 )

– Typeset by FoilTEX 89

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)

– Typeset by FoilTEX 90

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 -> )

– Typeset by FoilTEX 91

Rekursionsmuster (Merks¨atze)

aus dem Prinzipein Rekursionsmuster anwenden=jeden Konstruktor durch eine passende Funktion ersetzenfolgt:

•Anzahl der Muster-Argumente=Anzahl der Konstruktoren (plus eins f¨ur das Datenargument)

•Stelligkeit eines Muster-Argumentes=Stelligkeit des entsprechenden Konstruktors

•Rekursion im Typ⇒Rekursion im Muster (Bsp: zweites Argument vonCons)

•zu jedem rekursiven Datentyp gibt esgenau ein passendes Rekursionsmuster

– Typeset by FoilTEX 92

Rekursion ¨uber Listen ( ¨Ubung)

das vordefinierte Rekursionsschema ¨uber Listen ist:

foldr :: (a -> b -> b) -> b -> ([a] -> b) length = foldr ( \ x y -> 1 + y ) 0 Beachte:

•Argument-Reihenfolge (erst cons, dann nil)

•foldr nicht mit foldl verwechseln (foldr ist das ”richtige“) Aufgaben:

•append, reverse, concat, inits, tails mitfoldr(d. h., ohne Rekursion)

– Typeset by FoilTEX 93

Weitere Beispiele f ¨ur Folds

data Tree a = Leaf a | Branch (Tree a) (Tree a) fold :: ...

•Anzahl der Bl¨atter

•Anzahl der Verzweigungsknoten

•Summe der Schl¨ussel

•die Tiefe des Baumes

•der gr¨oßte Schl¨ussel

– Typeset by Foil 94

Rekursionsmuster (Peano-Zahlen)

data N = Z | S N

fold :: ...

fold z s n = case n of Z ->

S n’ ->

plus = fold ...

times = fold ...

– Typeset by Foil 95

(13)

¨Ubung Rekursionsmuster

•Rekursionsmusterfoldrf¨ur Listen benutzen (filter, takeWhile, append, reverse, concat, inits, tails)

•Rekursionmuster f¨ur Peano-Zahlen hinschreiben und benutzen (plus, mal, hoch, Nachfolger, Vorg¨anger, minus)

•Rekursionmuster f¨ur bin¨are B¨aume mit Schl¨usselnnur in den Bl¨atternhinschreiben und benutzen

•Rekursionmuster f¨ur bin¨are B¨aume mit Schl¨usselnnur in den Verzweigungsknotenbenutzen f¨ur rekursionslose Programme f¨ur:

Anzahl der Branch-Knoten ist ungerade (nicht z¨ahlen!) Baum (Tree a) erf¨ullt die AVL-Bedingung

– Typeset by FoilTEX 96

Hinweis: als Projektion auf die erste Komponente eines fold, das Paar vonBool(ist AVL-Baum) undInt (H¨ohe) berechnet.

Baum (Tree Int) ist Suchbaum (ohneinorder) Hinweis: als Projektion. Bestimme geeignete Hilfsdaten.

•Wende die Vorschrift zur Konstruktion des Rekursionsmusters an auf den Typ Bool

Maybe a Jeweils:

Typ und Implementierung Testf¨alle

gibt es diese Funktion bereits? Suche nach dem Typ mit

– Typeset by FoilTEX 97

https://www.stackage.org/lts-5.17/hoogle

– Typeset by FoilTEX 98

Objektorientierte Entwurfmuster

Definition, Geschichte

•Ziel: flexibel wiederverwendbarer sicherer Quelltext

•L¨osung:Funktionen h¨oherer Ordnung

•Simulation davon im OO-Paragidma:Entwurfsmuster wir wollen: Funktion als Datum (z.B. Lambda-Ausdruck), wir konstruieren: Objekt, das zu einer (anonymen) Klasse geh¨ort, die diese Funktion als Methode enth¨alt.

•Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides:Entwurfsmuster (design patterns)— Elemente wiederverwendbarer objektorientierter Software,

Addison-Wesley 1996.

– Typeset by FoilTEX 99

Beispiel Strategie-Muster

•Aufgabe: Sortieren einer Liste bzgl. w¨ahlbarer Ordnung auf Elementen.

•L¨osung (inData.List)

data Ordering = LT | EQ | GT

sortBy :: (a -> a -> Ordering) -> List a -> List a

( ¨U: implementiere durch unbalancierten Suchbaum)

•Simulation (injava.util.*)

interface Comparator<T> { int compare(T x, T y); } static <T> void sort(List<T> list,Comparator<T> c);

hier istceinStrategie-Objekt

– Typeset by FoilTEX 100

Algebraische Datentypen in OOP

Kompositum: Motivation

•Bsp: Gestaltung von zusammengesetzten Layouts.

Modell als algebraischer Datentyp:

data Component = JButton { ... }

| Container (List Component)

•Simulation durch EntwurfsmusterKompositum:

abstract class Component

class JButton extends Component class Container extends Component { void add (Component c); }

– Typeset by FoilTEX 101

Kompositum: Beispiel

public class Composite {

public static void main(String[] args) { JFrame f = new JFrame ("Composite");

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Container c = new JPanel (new BorderLayout());

c.add (new JButton ("foo"), BorderLayout.CENTER);

f.getContentPane().add(c);

f.pack(); f.setVisible(true);

} }

¨Ubung: geschachtelte Layouts bauen, vgl.

http://www.imn.htwk-leipzig.de/˜waldmann/

edu/ws06/informatik/manage/

– Typeset by Foil 102

Kompositum: Definition

•Definition:Kompositum=algebraischer Datentyp (ADT)

•ADTdata T = .. | C .. T ..

als Kompositum:

TypT⇒gemeinsame Basisklasse (interface) jeder KonstruktorC⇒implementierende Klasse jedes Argument des Konstruktors⇒Attribut der Klasse diese Argumente k¨onnenTbenutzen (rekursiver Typ) (Vorsicht: Begriff und Abk¨urzung nicht verwechseln mit abstrakter Datentyp=ein Typ, dessen Datenkonstruktoren wirnichtsehen)

– Typeset by Foil 103

(14)

Bin¨are B¨aume als Komposita

•Knoten sindinnere(Verzweigung) und¨außere(Blatt).

•Die richtige Realisierung ist Kompositum interface Tree<K>;

class Branch<K> implements Tree<K>;

class Leaf<K> implements Tree<K>;

•Schl¨ussel: in allen Knoten, nur innen, nur außen.

der entsprechende algebraische Datentyp ist:

data Tree k = Leaf { ... }

| Branch { left :: Tree k , ...

, right :: Tree k }

¨Ubung: Anzahl aller Bl¨atter, Summe aller Schl¨ussel (Typ?), der gr¨oßte Schl¨ussel (Typ?)

– Typeset by FoilTEX 104

Kompositum-Vermeidung

Wenn Bl¨atter keine Schl¨ussel haben, geht es musterfrei?

class Tree<K> {

Tree<K> left; K key; Tree<K> right;

}

Der entsprechende algebraische Datentyp ist data Tree k =

Tree { left :: Maybe (Tree k) , key :: k

, right :: Maybe (Tree k) }

erzeugt in Java das Problem, daß . . .

¨Ubung: betrachte Implementierung in java.util.Map<K,V>

– Typeset by FoilTEX 105

Maybe

=

Nullable

Algebraischer Datentyp (Haskell):

data Maybe a = Nothing | Just a http:

//hackage.haskell.org/packages/archive/

base/latest/doc/html/Prelude.html#t:Maybe In Sprachen mit Verweisen (auf Objekte vom TypO) gibt es h¨aufig auch ”Verweis auf kein Objekt“— auch vom TypO.

Deswegennull pointer exceptions.

Ursache ist Verwechslung vonMaybe amita.

Trennung in C#:Nullable<T>(f¨ur primitive TypenT) http://msdn.microsoft.com/en-us/library/

2cf62fcy.aspx

– Typeset by FoilTEX 106

Alg. DT und Pattern Matching in Scala

http://scala-lang.org

algebraische Datentypen:

abstract class Tree[A]

case class Leaf[A](key: A) extends Tree[A]

case class Branch[A]

(left: Tree[A], right: Tree[A]) extends Tree[A]

pattern matching:

def size[A](t: Tree[A]): Int = t match { case Leaf(k) => 1

case Branch(l, r) => size(l) + size(r) }

beachte: Typparameter in eckigen Klammern

– Typeset by FoilTEX 107

Objektorientierte Rekursionsmuster

Plan

•algebraischer Datentyp=Kompositum (Typ⇒Interface, Konstruktor⇒Klasse)

•Rekursionsschema=Besucher (Visitor) (Realisierung der Fallunterscheidung)

(Zum Vergleich von Java- und Haskell-Programmierung) sagte bereits Albert Einstein:Das Holzhacken ist deswegen so beliebt, weil man den Erfolg sofort sieht.

– Typeset by FoilTEX 108

Wiederholung Rekursionsschema

foldanwenden: jeden Konstruktor d. Funktion ersetzen

•Konstruktor⇒Schema-Argument

•. . . mit gleicher Stelligkeit

•Rekursion im Typ⇒Anwendung auf Schema-Resultat

data Tree a = Leaf a | Branch (Tree a) (Tree a) Leaf :: a -> Tree a

Branch :: Tree a -> Tree a -> Tree a

fold :: (a -> b) -> (b -> b -> b) -> Tree a -> b fold leaf branch t = case t of

Leaf k -> leaf k

Branch l r -> branch (fold leaf branch l) (fold leaf branch r) depth :: Tree a -> Int

depth = fold ( \ k -> 0 ) ( \ x y -> 1 + max x y )

– Typeset by FoilTEX 109

Wiederholung: Kompositum

Haskell: algebraischer Datentyp

data Tree a = Leaf a

| Branch (Tree a) (Tree a) Leaf :: a -> Tree a

Branch :: Tree a -> Tree a -> Tree a Java: Kompositum

interface Tree<A> { }

class Leaf<A> implements Tree<A> { A key; } class Branch<A> implements Tree<A> {

Tree<A> left; Tree<A> right;

}

(Scala: case class)

– Typeset by Foil 110

¨Ubung Kompositum

public class Main {

// vollst. Bin¨arbaum der Tiefe d

// mit Schl¨usseln 2ˆd * (c - 1) .. 2ˆd * c - 1 static Tree<Integer> build (int d, int c);

class Pair<A,B> { A first; B second; }

// (Schl¨ussel links außen, Schl. rechts außen) static <A> Pair<A,A> bounds (Tree<A> t);

public static void main(String[] args) { Tree<Integer> t = Main.build(4,1);

System.out.println (Main.bounds(t));

} }

– Typeset by Foil 111

(15)

Kompositum und Visitor

Definition eines Besucher-Objektes

(f¨ur Rekursionsmuster mit ResultattypR ¨uberTree<A>) entspricht einem Tupel von Funktionen

interface Visitor<A,R> { R leaf(A k);

R branch(R x, R y); } Empfangen eines Besuchers:

durch jeden Teilnehmer des Kompositums interface Tree<A> { ..

<R> R receive (Visitor<A,R> v); }

•Implementierung

•Anwendung (Bl¨atter z¨ahlen, Tiefe, Spiegelbild)

– Typeset by FoilTEX 112

Aufgabe: Besucher f ¨ur Listen

Schreibe das Kompositum f¨ur

data List a = Nil | Cons a (List a) und den passenden Besucher. Benutze f¨ur

•Summe, Produkt f¨urList<Integer>

•Und, Oder f¨urList<Boolean>

•Wert als gespiegelte Bin¨arzahl (LSB ist links) Bsp:[1,1,0,1] ==> 11

Quelltexte aus Vorlesung:

https://gitlab.imn.htwk-leipzig.de/

waldmann/fop-ss16

– Typeset by FoilTEX 113

Eine Funktion, die kein Fold ist

Das geht:f xs = die L¨ange von xs ist gerade f = fold True ( \ x y -> not y )

Das geht nicht:g xs = die L¨ange von xs ist >= 2 Beweis: falls dochg = fold nil cons, dann betrachte l0 = Nil ; g l0 = False -- nach Spez.

l1 = Cons 4 Nil ; g l1 = False -- nach Spez.

g (Cons 2 l0) = False -- nach Spezifikation g (Cons 2 l0) = cons 2 (g l0) = cons 2 False g (Cons 2 l1) = True -- nach Spezifikation g (Cons 2 l1) = cons 2 (g l1) = cons 2 False es folgt WiderspruchFalse = cons 2 False = True d.h. die Annahme (g = fold nil cons) ist falsch.

– Typeset by FoilTEX 114

Polymorphie

Arten der Polymorphie

•generische Polymorphie: erkennbar an Typvariablen zur ¨Ubersetzungszeit werden Typvariablen durch konkrete Typen substituiert,

•dynamische Polymorphie (≈Objektorientierung) erkennbar animplementszw. Klasse und Schnittstelle zurLaufzeitwird Methodenimplementierung ausgew¨ahlt moderne OO-Sprachen (u.a. Java, C#) bietenbeide Formen der Polymorphie

mitstatischer Sicherheit (d.h. statische Garantie, daß zur Laufzeit keine Methoden fehlen)

– Typeset by FoilTEX 115

Java-Notation f. generische Polymorphie

generischerTyp(Typkonstruktor):

•Deklaration der Typparameter:class C<S,T> {..}

•bei Benutzung Angabe der Typargumente (Pflicht):

{ C<Boolean,Integer> x = ... } statische generischeMethode:

•Deklaration:class C { static <T> int f(T x) }

•Benutzung:C.<Integer>f (3)

Typargumente k¨onnen auch inferiert werden.

( ¨Ubung: Angabe der Typargumente f¨ur polymorphe nicht statische Methode)

– Typeset by FoilTEX 116

Beispiel f. dynamische Polymorphie

interface I { int m (); }

class A implements I

{ int m () { return 0; }}

class B implements I

{ int m () { return 1; }}

I x = // statischer Typ von x ist I new A(); // dynamischer Typ ist hier A System.out.println (x.m());

x = new B(); // dynamischer Typ ist jetzt B System.out.println (x.m());

•statischer Typ: eines Bezeichners im Programmtext

•dynamischer Typ: einer Stelle im Speicher

– Typeset by FoilTEX 117

Klassen, Schnittstellen und Entwurfsmuster

•FP-Sichtweise: Entwurfsmuster=Fkt. h¨oherer Ordnung

•OO-Sichtweise: E.M.=n¨utzliche Beziehung zw. Klassen . . . die durch Schnittstellen ausgedr¨uckt wird.

⇒Verwendung von konkreten Typen (Klassen)ist ein Code Smell, es sollen soweit m¨oglich abstrakte Typen (Schnittstellen) sein. ( ¨U: diskutiereIEnumerable)

•insbesondere: in Java (ab 8):

funkionales Interface=hat genau eine Methode eine implementierende anonyme Klasse kann als Lambda-Ausdruck geschrieben werden

– Typeset by Foil 118

Erzwingen von Abstraktionen

•interface I { .. }

class C implements I { .. } ; Wie kannC x = new C()verhindert werden, undI x = new C()erzwungen?

•Ansatz:class C { private C() { } } aber dann ist auchI x = new C()verboten.

•L¨osung: Fabrik-Methode class C { ..

static I make () { return new C (); } }

– Typeset by Foil 119

(16)

Das Fabrik-Muster

interface I { }

class A implements I { A (int x) { .. } } class B implements I { B (int x) { .. } } die Gemeinsamkeit der Konstruktoren kann nicht inI ausgedr¨uckt werden.

interface F // abstrakte Fabrik { I construct (int x); }

class FA implements F // konkrete Fabrik { I construct (int x) { return new A(x); } } class FB implements F { .. }

main () {

F f = Eingabe ? new FA() : new FB();

I o1=f.construct(3); I o2=f.construct(4);

– Typeset by FoilTEX 120

Typklassen in Haskell: ¨Uberblick

•in einfachen Anwendungsf¨allen:

Typklasse in Haskell∼Schnittstelle in OO:

beschreibt Gemeinsamkeit von konkreten Typen

Bsp. der Typ hat eine totale Ordnung Haskell:class Ord a, Java:

interface Comparable<E>

Bsp. der Typ besitzt Abbildung nachString Haskellclass Show a, Java?

•unterschiedliche Benutzung und Implementierung Haskell - statisch, OO - dynamisch

– Typeset by FoilTEX 121

Beispiel

sortBy :: (a -> a -> Ordering) -> [a] -> [a]

sortBy ( \ x y -> ... ) [False, True, False]

Kann mit Typklassen so formuliert werden:

class Ord a where

compare :: a -> a -> Ordering sort :: Ord a => [a] -> [a]

instance Ord Bool where compare x y = ...

sort [False, True, False]

•sorthateingeschr¨ankt polymorphen Typ

•die Einschr¨ankung (das ConstraintOrd a) wird in ein zus¨atzliches Argument (eine Funktion) ¨ubersetzt.

Entspricht OO-Methodentabelle, liegt aberstatischfest.

– Typeset by FoilTEX 122

Unterschiede Typklasse/Interface (Bsp)

•Typklasse/Schnittstelle

class Show a where show :: a -> String interface Show { String show (); }

•Instanzen/Implementierungen

data A = .. ; instance Show A where ..

class A implements Show { .. }entspr. f¨urB

•in Java istShowein Typ:

static String showList(List<Show> xs) { .. } showList (Arrays.asList (new A(),new B())) in Haskell istShowein Typconstraint und kein Typ:

showList :: Show a => List a -> String showList [A,B]ist Typfehler

– Typeset by FoilTEX 123

Typklassen k ¨onnen mehr als Interfaces

in Java, C#, . . . kann Schnittstelle (interface) in

Deklarationen wie Typ (class) benutzt werden, das ist 1. praktisch, aber nur 2. soweit es eben geht

•(?) Fkt. mit>1Argument, Bsp. compareTo,

static <T extends Comparable<? super T>>

void sort(List<T> list)

•(–) Beziehungen zwischen mehreren Typen, class Autotool problem solution

•(–) Typkonstruktorklassen,

class Foldable c where toList :: c a -> [a];

data Tree a = ..;instance Foldable Tree (wichtig f¨ur fortgeschrittene Haskell-Programmierung)

– Typeset by FoilTEX 124

Grundwissen Typklassen

•Typklasse schr¨ankt statische Polymorphie ein (Typvariable darf nicht beliebig substitutiert werden)

•Einschr¨ankung realisiert durchW¨orterbuch-Argument (W.B.=Methodentabelle, Record von Funktionen)

•durch Instanz-Deklaration wird W¨orterbuch erzeugt

•bei Benutzung einer eingeschr¨ankt polymorphen Funktion: passendes W¨orterbuch wird statisch bestimmt

•n¨utzliche, h¨aufige Typklassen:Show,Read,Eq,Ord.

(Test.SmallCheck.Serial,Foldable,Monad,. . . )

•Instanzen automatisch erzeugen mitderiving

– Typeset by FoilTEX 125

¨Ubung Polymorphie

•Besucher f¨ur Listen-Kompositum hinzuf¨ugen (Quelltext aus VL), damit implementieren:

class Main {

static Boolean and (List<Boolean> xs) { return xs.receive(new ... );

}

public static void main (String [] argv) { List<Boolean> xs = new Cons<Boolean>(...);

syso (Main.and(xs);

} }

– Typeset by Foil 126

•nach Java ¨ubersetzen und implementieren

data Pair a b = Pair { first :: a, second :: b } swap :: Pair a b -> Pair b a

p :: Pair Int Bool ; p = Pair 3 False ; q = swap p

•autotool: Aufgabe zu Typklassen (unbalancierte Suchb¨aume)

– Typeset by Foil 127

Referenzen

ÄHNLICHE DOKUMENTE

Die Nutzung der Daten bleibt ausschließlich Jobnavi vorbehalten und darf nur im Rahmen einer Beratung mit einem Jugendlichen an Dritte weitergegeben werden.. Unsere Rechte

Der Workshop, eine Kooperation von ÖAW/IHB und dem Forschungsbereich Kunstgeschichte der TU Wien, nimmt dies zum Anlass und setzt sich anhand dreier spezifischer Fallbeispiele mit

wir wollen: Funktion als Datum (z.B. Lambda-Ausdruck), wir konstruieren: Objekt, das zu einer (anonymen) Klasse geh¨ort, die diese Funktion als Methode enth¨alt.. • Erich Gamma,

Refaktorisierung durch Funktionen Gegeben: (Code smell: duplizierter/¨ahnlicher Code) { int a =

Code Smell # 1: Duplicated Code jede Idee sollte an genau einer Stelle im Code formuliert werden:. Code

Abstract: Ausgehend von einigen grundsätzlichen Postulaten für einen allgemein bildenden Informatikunterricht in der Sekundarstufe 1 wird ein möglicher Lernweg skizziert, der von

[r]

[r]