• Keine Ergebnisse gefunden

I. Modularisierung und Abstrakte Datentypen

N/A
N/A
Protected

Academic year: 2022

Aktie "I. Modularisierung und Abstrakte Datentypen"

Copied!
6
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Praktische Informatik 3: Funktionale Programmierung Vorlesung 8 vom 21.12.2020: Abstrakte Datentypen

Christoph Lüth

Wintersemester 2020/21

11:51:27 2021-02-22 1 [44]

Organisatorisches

IAbgabe des 7. Übungsblattes in Gruppen zudreiStudenten.

IBittejetzteine Gruppe suchen!

IKlausurtermine:

IKlausur: 03.02.2020, 10:00/11:30/15:00 IWiederholungstermin: 21.04.2020, 10:00/11:30/15:00

PI3 WS 20/21 2 [44]

Fahrplan

ITeil I: Funktionale Programmierung im Kleinen ITeil II: Funktionale Programmierung im Großen

IAbstrakte Datentypen ISignaturen und Eigenschaften

ITeil III: Funktionale Programmierung im richtigen Leben

PI3 WS 20/21 3 [44]

Inhalt

IAbstrakte Datentypen IAllgemeine Einführung IRealisierung in Haskell IBeispiele

PI3 WS 20/21 4 [44]

I. Modularisierung und Abstrakte Datentypen

PI3 WS 20/21 5 [44]

Warum Modularisierung?

IÜbersichtlichkeit der Module Lesbarkeit

IGetrennte Übersetzung technischeHandhabbarkeit

IVerkapselung konzeptionelleHandhabbarkeit

PI3 WS 20/21 6 [44]

Abstrakte Datentypen

Definition (Abstrakter Datentyp)

Einabstrakter Datentyp(ADT) besteht aus einem (oder mehreren)Typenund Operationendarauf, mit folgenden Eigenschaften:

1Werte des Typen können nur über die Operationenerzeugtwerden

2Eigenschaften von Werten des Typen werden nur über die Operationenbeobachtet 3Einhaltung vonInvariantenüber dem Typ kann garantiert werden

Implementationvon ADTs in einer Programmiersprache:

Ibenötigt Möglichkeit derKapselung(Einschränkung der Sichtbarkeit) Ibspw. durchModuleoderObjekte

PI3 WS 20/21 7 [44]

ADTs vs. algebraische Datentypen

IAlgebraische Datentypen IFrei erzeugtdurchKonstruktoren IKeine Einschränkungen

IInsbesondere keine Gleichheiten der Konstruktoren ([ ]6=x:xs,x:ls6=y:lsetc.) IADTs:

IKeine ausgezeichneten Konstruktoren IEinschränkungen und Invarianten möglich IGleichheiten möglich

PI3 WS 20/21 8 [44]

(2)

ADTs vs. Objekte

IADTs (z.B. Haskell):TypplusOperationen IObjekte (z.B. Java):Interface,Methoden.

IGemeinsamkeiten:

IVerkapselung(information hiding) der Implementation IUnterschiede:

IObjekte habeninternen Zustand, ADTs sindreferentiell transparent;

IObjekte habenKonstruktoren, ADTs nicht

IVererbungsstrukturauf Objekten (Verfeinerungfür ADTs) IJava:interfaceeigenes Sprachkonstrukt

IJava:packagesfür Sichtbarkeit

PI3 WS 20/21 9 [44]

ADTs in Haskell: Module

IEinschränkung der Sichtbarkeit durchVerkapselung IModul: Kleinste verkapselbareEinheit

IEinModulumfaßt:

IDefinitionenvon Typen, Funktionen, Klassen IDeklarationder nach außensichtbarenDefinitionen

IGleichzeitig: Modul ˆ= Übersetzungseinheit (getrennte Übersetzung)

PI3 WS 20/21 10 [44]

Module: Syntax

ISyntax:

moduleName(Bezeichner)whereRumpf IBezeichner können leer sein (dann wird alles exportiert) IBezeichner sind:

ITypen:T,T(c1,..., cn),T(..) IKlassen:C,C(f1,...,fn),C(..)

IAndere Bezeichner:Werte,Felder,Klassenmethoden IImportierteModule:moduleM

ITypsynonyme und Klasseninstanzen bleiben sichtbar IModule könnenrekursivsein(don’t try at home)

PI3 WS 20/21 11 [44]

Refakturierung im Einkaufsparadies

module Shoppe4 where import Data.Maybe

−−Modellierung der Artikel.

data Apfelsorte = Boskoop | CoxOrange | GrannySmithderiving (Eq, Show) apreis :: Apfelsorte→Int apreis Boskoop = 55 apreis CoxOrange = 60 apreis GrannySmith = 50 data Kaesesorte = Gouda | Appenzellerderiving (Eq, Show) kpreis :: Kaesesorte→Double kpreis Gouda = 1450 kpreis Appenzeller = 2270 data Bio = Bio | Konv

deriving (Eq, Show) data Artikel =

Apfel Apfelsorte | Eier

| Kaese Kaesesorte | Schinken

| Salami | Milch Bio deriving (Eq, Show) data Menge = Stueck Int | Gramm Int | Liter Double

deriving (Eq, Show) type Preis = Maybe Int preis :: Artikel→Menge→Preis preis (Apfel a) (Stueck n) = J ust (n∗apreis a) preis Eier (Stueck n)= J ust (n∗20) preis (Kaese k)(Gramm g) = J ust (round( fromIntegral g∗1000∗kpreis k)) preis Schinken (Gramm g) = J ust ( div (g∗199) 100) preis Salami (Gramm g)= J ust ( div (g∗159) 100) preis (Milch bio) ( Liter l ) =

J ust (round ( l∗case bio of Bio→119; Konv→69)) preis = Nothing

−−Addition von Mengenaddiere :: Menge→Menge→Menge addiere (Stueck i ) (Stueck j )= Stueck ( i + j ) addiere (Gramm g) (Gramm h) = Gramm (g+ h) addiere ( Liter l ) ( Liter m) = Liter ( l +m) addiere m n = error (”addiere: ”++ show m++ ” und ”++ show n)

−−Posten:

data Posten = Posten Artikel Mengederiving (Eq, Show) cent :: Posten→Int

cent (Posten a m) = fromMaybe 0 ( preis a m)−−gibt keinen Laufzeitfehler!

−−Lagerhaltung:data Lager = Lager [Posten]

deriving (Eq, Show) leeresLager :: Lager leeresLager = Lager []

suche :: Artikel→Lager→Maybe Menge suche a (Lager ps) =

listToMaybe [ m | Posten la m←ps,la == a ] einlagern :: Artikel→Menge→Lager→Lager einlagern a m (Lager ps) =

let hinein a m [] = [Posten a m]

hinein a m (Posten al ml: l )| a == al= (Posten a ( addiere m ml): l )

| otherwise = (Posten al ml: hinein a m l ) in case preis a m of

Nothing→Lager psLager ( hinein a m ps) data Einkaufswagen = Ekwg [Posten]

deriving (Eq, Show) leererWagen :: Einkaufswagen leererWagen = Ekwg []

einkauf :: Artikel→Menge→Einkaufswagen→Einkaufswagen einkauf a m (Ekwg ps)

| isJ ust ( preis a m) = Ekwg (Posten a m: ps)

| otherwise = Ekwg ps kasse :: Einkaufswagen→Int kasse (Ekwg ps) = sum (map cent ps) kassenbon :: Einkaufswagen→String kassenbon ew@(Ekwg ps) =

”Bob’ s Aulde Grocery Shoppe\ n\ n”++

”Artikel Menge Preis\ n”++

”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\ n”++

concatMap artikel ps ++

”=====================================\ n”++

”Summe:”++ formatR 31 (showEuro (kasse ew)) artikel :: Posten→String artikel p@(Posten a m) =

formatL 20 (show a) ++

formatR 7 (menge m) ++

formatR 10 (showEuro (cent p)) ++ ”\ n”

menge :: Menge→String menge (Stueck n) = show n++ ” St”

menge (Gramm g) = show g++ ” g.”

menge ( Liter l ) = show l++ ” l .”

formatL :: Int→String→String formatL n str = take n ( str++ replicate n ’ ’) formatR :: Int→String→String formatR n str =take n ( replicate (n−length str) ’ ’++ str) showEuro :: Int→String showEuro i =

show ( div i 100) ++ ”.”++

show (mod ( div i 10) 10) ++

show (mod i 10)++ ” EU”

inventur :: Lager→Int inventur (Lager l ) = sum (map cent l )

Artikel

module Shoppe4 where import Data.Maybe

−−Modellierung der Artikel.

data Apfelsorte = Boskoop | CoxOrange | GrannySmithderiving (Eq, Show) apreis :: Apfelsorte→Int apreis Boskoop = 55 apreis CoxOrange = 60 apreis GrannySmith = 50 data Kaesesorte = Gouda | Appenzellerderiving (Eq, Show) kpreis :: Kaesesorte→Double kpreis Gouda = 1450 kpreis Appenzeller = 2270 data Bio = Bio | Konv

deriving (Eq, Show) data Artikel =

Apfel Apfelsorte | Eier

| Kaese Kaesesorte | Schinken

| Salami | Milch Bio deriving (Eq, Show) data Menge = Stueck Int | Gramm Int | Liter Double

deriving (Eq, Show) type Preis = Maybe Int preis :: Artikel→Menge→Preis preis (Apfel a) (Stueck n) = J ust (n∗apreis a) preis Eier (Stueck n)= J ust (n∗20) preis (Kaese k)(Gramm g) = J ust (round( fromIntegral g∗1000∗kpreis k)) preis Schinken (Gramm g) = J ust ( div (g∗199) 100) preis Salami (Gramm g)= J ust ( div (g∗159) 100) preis (Milch bio) ( Liter l ) =

J ust (round ( l∗case bio of Bio→119; Konv→69)) preis = Nothing

−−Addition von Mengenaddiere :: Menge→Menge→Menge addiere (Stueck i ) (Stueck j )= Stueck ( i + j ) addiere (Gramm g) (Gramm h) = Gramm (g+ h) addiere ( Liter l ) ( Liter m) = Liter ( l +m) addiere m n = error (”addiere: ”++ show m++ ” und ”++ show n)

−−Posten:

data Posten = Posten Artikel Mengederiving (Eq, Show) cent :: Posten→Int

cent (Posten a m) = fromMaybe 0 ( preis a m)−−gibt keinen Laufzeitfehler!

−−Lagerhaltung:data Lager = Lager [Posten]

deriving (Eq, Show) leeresLager :: Lager leeresLager = Lager []

suche :: Artikel→Lager→Maybe Menge suche a (Lager ps) =

listToMaybe [ m | Posten la m←ps,la == a ] einlagern :: Artikel→Menge→Lager→Lager einlagern a m (Lager ps) =

let hinein a m [] = [Posten a m]

hinein a m (Posten al ml: l )| a == al= (Posten a ( addiere m ml): l )

| otherwise = (Posten al ml: hinein a m l ) in case preis a m of

Nothing→Lager psLager ( hinein a m ps) data Einkaufswagen = Ekwg [Posten]

deriving (Eq, Show) leererWagen :: Einkaufswagen leererWagen = Ekwg []

einkauf :: Artikel→Menge→Einkaufswagen→Einkaufswagen einkauf a m (Ekwg ps)

| isJ ust ( preis a m) = Ekwg (Posten a m: ps)

| otherwise = Ekwg ps kasse :: Einkaufswagen→Int kasse (Ekwg ps) = sum (map cent ps) kassenbon :: Einkaufswagen→String kassenbon ew@(Ekwg ps) =

”Bob’ s Aulde Grocery Shoppe\ n\ n”++

”Artikel Menge Preis\ n”++

”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\ n”++

concatMap artikel ps ++

”=====================================\ n”++

”Summe:”++ formatR 31 (showEuro (kasse ew)) artikel :: Posten→String artikel p@(Posten a m) =

formatL 20 (show a) ++

formatR 7 (menge m) ++

formatR 10 (showEuro (cent p)) ++ ”\ n”

menge :: Menge→String menge (Stueck n) = show n++ ” St”

menge (Gramm g) = show g++ ” g.”

menge ( Liter l ) = show l++ ” l .”

formatL :: Int→String→String formatL n str = take n ( str++ replicate n ’ ’) formatR :: Int→String→String formatR n str =take n ( replicate (n−length str) ’ ’++ str) showEuro :: Int→String showEuro i =

show ( div i 100) ++ ”.”++

show (mod ( div i 10) 10) ++

show (mod i 10)++ ” EU”

inventur :: Lager→Int inventur (Lager l ) = sum (map cent l )

Posten Artikel

module Shoppe4 where import Data.Maybe

−−Modellierung der Artikel.

data Apfelsorte = Boskoop | CoxOrange | GrannySmithderiving (Eq, Show) apreis :: Apfelsorte→Int apreis Boskoop = 55 apreis CoxOrange = 60 apreis GrannySmith = 50 data Kaesesorte = Gouda | Appenzellerderiving (Eq, Show) kpreis :: Kaesesorte→Double kpreis Gouda = 1450 kpreis Appenzeller = 2270 data Bio = Bio | Konv

deriving (Eq, Show) data Artikel =

Apfel Apfelsorte | Eier

| Kaese Kaesesorte | Schinken

| Salami | Milch Bio deriving (Eq, Show) data Menge = Stueck Int | Gramm Int | Liter Double

deriving (Eq, Show) type Preis = Maybe Int preis :: Artikel→Menge→Preis preis (Apfel a) (Stueck n) = J ust (n∗apreis a) preis Eier (Stueck n)= J ust (n∗20) preis (Kaese k)(Gramm g) = J ust (round( fromIntegral g∗1000∗kpreis k)) preis Schinken (Gramm g) = J ust ( div (g∗199) 100) preis Salami (Gramm g)= J ust ( div (g∗159) 100) preis (Milch bio) ( Liter l ) =

J ust (round ( l∗case bio of Bio→119; Konv→69)) preis = Nothing

−−Addition von Mengenaddiere :: Menge→Menge→Menge addiere (Stueck i ) (Stueck j )= Stueck ( i + j ) addiere (Gramm g) (Gramm h) = Gramm (g+ h) addiere ( Liter l ) ( Liter m) = Liter ( l +m) addiere m n = error (”addiere: ”++ show m++ ” und ”++ show n)

−−Posten:

data Posten = Posten Artikel Mengederiving (Eq, Show) cent :: Posten→Int

cent (Posten a m) = fromMaybe 0 ( preis a m)−−gibt keinen Laufzeitfehler!

−−Lagerhaltung:data Lager = Lager [Posten]

deriving (Eq, Show) leeresLager :: Lager leeresLager = Lager []

suche :: Artikel→Lager→Maybe Menge suche a (Lager ps) =

listToMaybe [ m | Posten la m←ps,la == a ] einlagern :: Artikel→Menge→Lager→Lager einlagern a m (Lager ps) =

let hinein a m [] = [Posten a m]

hinein a m (Posten al ml: l )| a == al= (Posten a ( addiere m ml): l )

| otherwise = (Posten al ml: hinein a m l ) in case preis a m of

Nothing→Lager psLager ( hinein a m ps) data Einkaufswagen = Ekwg [Posten]

deriving (Eq, Show) leererWagen :: Einkaufswagen leererWagen = Ekwg []

einkauf :: Artikel→Menge→Einkaufswagen→Einkaufswagen einkauf a m (Ekwg ps)

| isJ ust ( preis a m) = Ekwg (Posten a m: ps)

| otherwise = Ekwg ps kasse :: Einkaufswagen→Int kasse (Ekwg ps) = sum (map cent ps) kassenbon :: Einkaufswagen→String kassenbon ew@(Ekwg ps) =

”Bob’ s Aulde Grocery Shoppe\ n\ n”++

”Artikel Menge Preis\ n”++

”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\ n”++

concatMap artikel ps ++

”=====================================\ n”++

”Summe:”++ formatR 31 (showEuro (kasse ew)) artikel :: Posten→String artikel p@(Posten a m) =

formatL 20 (show a) ++

formatR 7 (menge m) ++

formatR 10 (showEuro (cent p)) ++ ”\ n”

menge :: Menge→String menge (Stueck n) = show n++ ” St”

menge (Gramm g) = show g++ ” g.”

menge ( Liter l ) = show l++ ” l .”

formatL :: Int→String→String formatL n str = take n ( str++ replicate n ’ ’) formatR :: Int→String→String formatR n str =take n ( replicate (n−length str) ’ ’++ str) showEuro :: Int→String showEuro i =

show ( div i 100) ++ ”.”++

show (mod ( div i 10) 10) ++

show (mod i 10)++ ” EU”

inventur :: Lager→Int inventur (Lager l ) = sum (map cent l )

Lager

Lager Posten Artikel

module Shoppe4 where import Data.Maybe

−−Modellierung der Artikel.

data Apfelsorte = Boskoop | CoxOrange | GrannySmithderiving (Eq, Show) apreis :: Apfelsorte→Int apreis Boskoop = 55 apreis CoxOrange = 60 apreis GrannySmith = 50 data Kaesesorte = Gouda | Appenzellerderiving (Eq, Show) kpreis :: Kaesesorte→Double kpreis Gouda = 1450 kpreis Appenzeller = 2270 data Bio = Bio | Konv

deriving (Eq, Show) data Artikel =

Apfel Apfelsorte | Eier

| Kaese Kaesesorte | Schinken

| Salami | Milch Bio deriving (Eq, Show) data Menge = Stueck Int | Gramm Int | Liter Double

deriving (Eq, Show) type Preis = Maybe Int preis :: Artikel→Menge→Preis preis (Apfel a) (Stueck n) = J ust (n∗apreis a) preis Eier (Stueck n)= J ust (n∗20) preis (Kaese k)(Gramm g) = J ust (round( fromIntegral g∗1000∗kpreis k)) preis Schinken (Gramm g) = J ust ( div (g∗199) 100) preis Salami (Gramm g)= J ust ( div (g∗159) 100) preis (Milch bio) ( Liter l ) =

J ust (round ( l∗case bio of Bio→119; Konv→69)) preis = Nothing

−−Addition von Mengenaddiere :: Menge→Menge→Menge addiere (Stueck i ) (Stueck j )= Stueck ( i + j ) addiere (Gramm g) (Gramm h) = Gramm (g+ h) addiere ( Liter l ) ( Liter m) = Liter ( l +m) addiere m n = error (”addiere: ”++ show m++ ” und ”++ show n)

−−Posten:

data Posten = Posten Artikel Mengederiving (Eq, Show) cent :: Posten→Int

cent (Posten a m) = fromMaybe 0 ( preis a m)−−gibt keinen Laufzeitfehler!

−−Lagerhaltung:data Lager = Lager [Posten]

deriving (Eq, Show) leeresLager :: Lager leeresLager = Lager []

suche :: Artikel→Lager→Maybe Menge suche a (Lager ps) =

listToMaybe [ m | Posten la m←ps,la == a ] einlagern :: Artikel→Menge→Lager→Lager einlagern a m (Lager ps) =

let hinein a m [] = [Posten a m]

hinein a m (Posten al ml: l )| a == al= (Posten a ( addiere m ml): l )

| otherwise = (Posten al ml: hinein a m l ) in case preis a m of

Nothing→Lager psLager ( hinein a m ps) data Einkaufswagen = Ekwg [Posten]

deriving (Eq, Show) leererWagen :: Einkaufswagen leererWagen = Ekwg []

einkauf :: Artikel→Menge→Einkaufswagen→Einkaufswagen einkauf a m (Ekwg ps)

| isJ ust ( preis a m) = Ekwg (Posten a m: ps)

| otherwise = Ekwg ps kasse :: Einkaufswagen→Int kasse (Ekwg ps) = sum (map cent ps) kassenbon :: Einkaufswagen→String kassenbon ew@(Ekwg ps) =

”Bob’ s Aulde Grocery Shoppe\ n\ n”++

”Artikel Menge Preis\ n”++

”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\ n”++

concatMap artikel ps ++

”=====================================\ n”++

”Summe:”++ formatR 31 (showEuro (kasse ew)) artikel :: Posten→String artikel p@(Posten a m) =

formatL 20 (show a) ++

formatR 7 (menge m) ++

formatR 10 (showEuro (cent p)) ++ ”\ n”

menge :: Menge→String menge (Stueck n) = show n++ ” St”

menge (Gramm g) = show g++ ” g.”

menge ( Liter l ) = show l++ ” l .”

formatL :: Int→String→String formatL n str = take n ( str++ replicate n ’ ’) formatR :: Int→String→String formatR n str =take n ( replicate (n−length str) ’ ’++ str) showEuro :: Int→String showEuro i =

show ( div i 100) ++ ”.”++

show (mod ( div i 10) 10) ++

show (mod i 10)++ ” EU”

inventur :: Lager→Int inventur (Lager l ) = sum (map cent l )

Einkaufswagen Lager

Lager Posten Artikel

module Shoppe4 where import Data.Maybe

−−Modellierung der Artikel.

data Apfelsorte = Boskoop | CoxOrange | GrannySmithderiving (Eq, Show) apreis :: Apfelsorte→Int apreis Boskoop = 55 apreis CoxOrange = 60 apreis GrannySmith = 50 data Kaesesorte = Gouda | Appenzellerderiving (Eq, Show) kpreis :: Kaesesorte→Double kpreis Gouda = 1450 kpreis Appenzeller = 2270 data Bio = Bio | Konv

deriving (Eq, Show) data Artikel =

Apfel Apfelsorte | Eier

| Kaese Kaesesorte | Schinken

| Salami | Milch Bio deriving (Eq, Show) data Menge = Stueck Int | Gramm Int | Liter Double

deriving (Eq, Show) type Preis = Maybe Int preis :: Artikel→Menge→Preis preis (Apfel a) (Stueck n) = J ust (n∗apreis a) preis Eier (Stueck n)= J ust (n∗20) preis (Kaese k)(Gramm g) = J ust (round( fromIntegral g∗1000∗kpreis k)) preis Schinken (Gramm g) = J ust ( div (g∗199) 100) preis Salami (Gramm g)= J ust ( div (g∗159) 100) preis (Milch bio) ( Liter l ) =

J ust (round ( l∗case bio of Bio→119; Konv→69)) preis = Nothing

−−Addition von Mengenaddiere :: Menge→Menge→Menge addiere (Stueck i ) (Stueck j )= Stueck ( i + j ) addiere (Gramm g) (Gramm h) = Gramm (g+ h) addiere ( Liter l ) ( Liter m) = Liter ( l +m) addiere m n = error (”addiere: ”++ show m++ ” und ”++ show n)

−−Posten:

data Posten = Posten Artikel Mengederiving (Eq, Show) cent :: Posten→Int

cent (Posten a m) = fromMaybe 0 ( preis a m)−−gibt keinen Laufzeitfehler!

−−Lagerhaltung:data Lager = Lager [Posten]

deriving (Eq, Show) leeresLager :: Lager leeresLager = Lager []

suche :: Artikel→Lager→Maybe Menge suche a (Lager ps) =

listToMaybe [ m | Posten la m←ps,la == a ] einlagern :: Artikel→Menge→Lager→Lager einlagern a m (Lager ps) =

let hinein a m [] = [Posten a m]

hinein a m (Posten al ml: l )| a == al= (Posten a ( addiere m ml): l )

| otherwise = (Posten al ml: hinein a m l ) in case preis a m of

Nothing→Lager psLager ( hinein a m ps) data Einkaufswagen = Ekwg [Posten]

deriving (Eq, Show) leererWagen :: Einkaufswagen leererWagen = Ekwg []

einkauf :: Artikel→Menge→Einkaufswagen→Einkaufswagen einkauf a m (Ekwg ps)

| isJ ust ( preis a m) = Ekwg (Posten a m: ps)

| otherwise = Ekwg ps kasse :: Einkaufswagen→Int kasse (Ekwg ps) = sum (map cent ps) kassenbon :: Einkaufswagen→String kassenbon ew@(Ekwg ps) =

”Bob’ s Aulde Grocery Shoppe\ n\ n”++

”Artikel Menge Preis\ n”++

”−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\ n”++

concatMap artikel ps ++

”=====================================\ n”++

”Summe:”++ formatR 31 (showEuro (kasse ew)) artikel :: Posten→String artikel p@(Posten a m) =

formatL 20 (show a) ++

formatR 7 (menge m) ++

formatR 10 (showEuro (cent p)) ++ ”\ n”

menge :: Menge→String menge (Stueck n) = show n++ ” St”

menge (Gramm g) = show g++ ” g.”

menge ( Liter l ) = show l++ ” l .”

formatL :: Int→String→String formatL n str = take n ( str++ replicate n ’ ’) formatR :: Int→String→String formatR n str =take n ( replicate (n−length str) ’ ’++ str) showEuro :: Int→String showEuro i =

show ( div i 100) ++ ”.”++

show (mod ( div i 10) 10) ++

show (mod i 10)++ ” EU”

inventur :: Lager→Int inventur (Lager l ) = sum (map cent l )

PI3 WS 20/21 12 [44]

Refakturierung im Einkaufsparadies: Modularchitektur

Artikel

Shoppe

Lager Einkaufswagen

Posten

PI3 WS 20/21 13 [44]

Refakturierung im Einkaufsparadies I: Artikel

IEs wirdallesexportiert IReine Datenmodellierung

moduleArtikelwhere

data Apfelsorte=Boskoop | CoxOrange | GrannySmith apreis :: Apfelsorte →Int

data Kaesesorte=Gouda | Appenzeller kpreis :: Kaesesorte →Double

data Menge=Stueck Int | Gramm Int | Liter Double addiere :: Menge→Menge→Menge

PI3 WS 20/21 14 [44]

Refakturierung im Einkaufsparadies II: Posten

modulePosten(

Posten, artikel, menge, posten, cent, hinzu)where

IImplementiert ADTPosten:

data Posten=Posten Artikel Menge deriving(Eq, Show) artikel :: Posten→ Artikel artikel (Posten a _)=a IKonstruktor wirdnichtexportiert

IInvariante:Postenhat immer die korrekte Menge zu Artikel posten :: Artikel→Menge→Maybe Posten posten a m=

casepreis a mof

Just _ →Just (Posten a m) Nothing→Nothing

Refakturierung im Einkaufsparadies III: Lager

moduleLager(

Lager, leeresLager, einlagern, suche, liste, inventur )where importArtikel importPosten

IImplementiert ADTLager dataLager

ISignatur der exportierten Funktionen:

leeresLager :: Lager

einlagern :: Artikel→Menge→Lager→Lager suche a (Lager l)= M.lookup a l

liste (Lager m)=M.toList m

inventur=sum◦map (fromJust◦uncurry preis)◦liste IInvariante:Lagerenthält keine doppelten Artikel

(3)

Refakturierung im Einkaufsparadies IV: Einkaufswagen

moduleEinkaufswagen(

Einkaufswagen, leererWagen, einkauf, kasse, kassenbon )where

IADT durchVerkapselung:

data Einkaufswagen=Ekwg [Posten]

deriving(Eq, Show) IEin Typsynmonym würde exportiert

IInvariante: Korrekte Menge zu Artikel im Einkaufswagen einkauf :: Artikel→ Menge→Einkaufswagen

→Einkaufswagen einkauf a m (Ekwg ps)=caseposten a mof

Just p→ Ekwg (p: ps) Nothing →Ekwg ps INutzt dazu ADTPosten

PI3 WS 20/21 17 [44]

Refakturierung im Einkaufsparadies V: Hauptmodul

moduleShoppewhere importArtikel importLager importEinkaufswagen

INutzt andere Module w0= leererWagen

w1= einkauf ( Apfel Boskoop) (Stueck 3) w0 w2= einkauf Schinken (Gramm 50) w1 w3= einkauf (Milch Bio) ( L i t e r 1) w2 w4= einkauf Schinken (Gramm 50) w3

PI3 WS 20/21 18 [44]

Benutzung von ADTs

IOperationenundTypenmüssenimportiertwerden

IMöglichkeiten des Imports:

IAllesimportieren

INur bestimmteOperationen und Typenimportieren IBestimmteTypen und Operationennichtimportieren

PI3 WS 20/21 19 [44]

Importe in Haskell

ISyntax:

import[qualified] M [as N] [hiding][(Bezeichner)]

IBezeichnergeben an,wasimportiert werden soll:

IOhne Bezeichner wirdallesimportiert IMithidingwerden Bezeichnernichtimportiert IFür jeden exportierten BezeichnerfausMwird importiert

IfundqualifizierterBezeichnerM.f Iqualified:nur qualifizierterBezeichnerM.f IUmbenennung bei Import mitas(dannN.f)

IKlasseninstanzen und Typsynonyme werden immer importiert IAlle Importe stehen immer amAnfangdes Moduls

PI3 WS 20/21 20 [44]

Beispiel

moduleM(a,b)where ...

Import(e) Bekannte Bezeichner

importM a,b,M.a,M.b

importM() (nothing)

importM(a) a,M.a

import qualifiedM M.a,M.b import qualifiedM() (nothing) import qualifiedM(a) M.a importMhiding() a,b,M.a,M.b importMhiding(a) b,M.b import qualifiedMhiding() M.a,M.b import qualifiedMhiding(a) M.b importM as B a,b,B.a,B.b

importM as B(a) a,B.a

import qualifiedM as B B.a,B.b

Quelle: Haskell98-Report, Sect. 5.3.4

PI3 WS 20/21 21 [44]

Ein typisches Beispiel

IModul implementiert Funktion, die auch importiert wird IUmbenennung nicht immer praktisch

IQualifizierter Import führt zulangenBezeichnern

IEinkaufswagenimplementiert Funktionenartikelundmenge, die auch ausPosten importiert werden:

importPostenhiding(artikel, menge) import qualifiedPosten as P(artikel, menge) artikel :: Posten→String

artikel p=

formatL 20 (show (P.artikel p)) ++ formatR 7 (menge (P.menge p))++ formatR 10 (showEuro (cent p))++"\n"

PI3 WS 20/21 22 [44]

Was zum Nachdenken

Übung 8.1: Import Warum schreibt man

importPreludehiding(repeat)

und was bewirkt das? (Hinweis:Preludeist das Modul der vordefinierten Funktionen.) Lösung:Die Import-Anweisung import alle vordefinierten Funktionenbis aufrepeat.

Dadurch können wirrepeatselber (anders) definieren.

PI3 WS 20/21 23 [44]

II. Schnittstelle vs. Implementation

PI3 WS 20/21 24 [44]

(4)

Schnittstelle vs. Implementation

IGleicheSchnittstellekann unterschiedlicheImplementationenhaben

IBeispiel: (endliche) Abbildungen

PI3 WS 20/21 25 [44]

Endliche Abbildungen

IViel gebraucht, oft in Abwandlungen (Hashtables, Sets, Arrays) IAbstrakter Datentyp fürendliche Abbildungen:

IDatentyp dataMapα β ILeere Abbildung:

empty :: Mapα β IAbbildung auslesen:

lookup :: Ordα⇒α→Mapα β→Maybeβ IAbbildung ändern:

insert :: Ordα⇒α→β→Mapα β→Mapα β IAbbildung löschen:

delete :: Ordα⇒α→Mapα β→Mapα β

PI3 WS 20/21 26 [44]

Eine naheliegende Implementation

IModellierung als Haskell-Funktion:

data Mapα β=Map (α→Maybeβ) IDamit einfacheslookup,insert,delete:

empty=Map (λx→Nothing) lookup a (Map s)=s a

insert a b (Map s)=Map (λx→ifx==a thenJust belses x) delete a (Map s)=Map (λx→if x==athen Nothingelses x) IInstanzen von Eq, Shownicht möglich

ISpeicherleck: überschriebene Zellen werden nicht freigegeben

PI3 WS 20/21 27 [44]

Endliche Abbildungen: Anwendungsbeispiel

ILager als endliche Abbildung:

dataLager=Lager (M.Map Artikel Menge) IArtikel suchen:

suche a (Lager l)= M.lookup a l IIns Lager hinzufügen:

einlagern :: Artikel→Menge→Lager→Lager einlagern a m (Lager l)=caseposten a mof

Just _ →case M.lookup a lof

Just q → Lager (M.insert a (addiere m q) l) Nothing→ Lager (M.insert a m l)

Nothing→Lager l

IFür Inventur fehlt Möglichkeit zurIteration IDaher: Map alsAssoziativliste

PI3 WS 20/21 28 [44]

Mitmachfolie

Übung 8.2: DieMapals Assoziativliste dataMapα β=Map [(α,β)]

insert :: Ordα⇒α→β→Mapα β→ Mapα β insert a b m=(a,b):m

Was ist der Nachteil dieser einfachen Implementation?

Lösung:Erzeugt ein Speicherleck — überschriebene Elemente bleiben in der Liste. Besser:

beim Einfügen alte Elemente entfernen

insert :: Ordα⇒α→β→Mapα β→ Mapα β insert a b xs=(a, b): filter ((a6=).fst) xs Nicht sehr effizient. Besser:MapalssortierteListe.

PI3 WS 20/21 29 [44]

Map als sortierte Assoziativliste

data Mapα β=Map { toList :: [(α,β)] }

IInvariante: Liste ist in der ersten Komponente aufsteigend sortiert Ilookupist vordefiniert; beim einfügen auch überschreiben;

insert :: Ordα⇒α→β→Mapα β→Mapα β insert a v (Map s)=Map (insert’ s)where

insert’ [ ] =[(a, v)]

insert’ s0@((b, w):s) | a> b=(b, w): insert’ s

| a==b=(a, v): s

| a< b=(a, v): s0 I. . . ist aberineffizient(Zugriff/Löschen inO(n)) IDeshalb:balancierte Bäume

PI3 WS 20/21 30 [44]

AVL-Bäume und Balancierte Bäume

AVL-Bäume

Ein Baum istausgeglichen, wenn Ialle Unterbäume ausgeglichen sind, und

Ider Höhenunterschied zwischen zwei Unterbäumen höchstens eins beträgt.

Balancierte Bäume Ein Baum istbalanciert, wenn Ialle Unterbäume balanciert sind, und Ifür den linken und rechten Unterbauml,rgilt:

size(l)w·size(r) (1)

size(r)w·size(l) (2)

wGewichtung(Parameter des Algorithmus)

Implementation

IBalanciertheit istInvariante

INach Einfügen oder Löschen: Balanciertheit wiederherstellen IDabei drei Fälle:

1 Linker Unterbaum größersize(l)>w·size(r)

2 Rechter Unterbaum größersize(r)>w· · ·size(l) 3 Keiner größer — Baum balanciert

(5)

Balanciertheit durch Einfache Rotation

ISei der rechte Unterbaum größer IZwei Unterfälle:

1 Linkes Enkelkindt2größer 2 Rechtes Enkelkindt3größer

IEinfacheLinksrotationheilt (2) IAnsonsten:Doppelrotationreduziert (1)

zu (2)

k1

t1 k2

t2 t3

Linksrotation

−−−−−−−−−−−−−−→

Rechtsrotation

←−−−−−−−−−−−−−−

k2

k1

t1 t2

t3

PI3 WS 20/21 33 [44]

Balanciertheit durch Doppelrotation

Falls linkes Enkelkind um Faktorαgrößer als rechtes:

INach einer einfachen Rechtsrotation des Unterbaumes ist rechtes Enkelkind größer IDanach Linksrotation des gesamten Baumes

k1

t1 k2

k3 t2 t3

t4

Rechtsrotation

−−−−−−−−→

k1 t1 k3

t2 k2 t3 t4

Linksrotation

−−−−−−−−→ k3 k1 t1 t2

k2 t3 t4

PI3 WS 20/21 34 [44]

Implementation in Haskell

IDer Datentyp data Mapα β=Empty

| Nodeα βInt (Mapα β) (Mapα β) derivingEq

IParameter:

IweightGewichtsfaktorw(für Einfachrotation) IratioGewichtsfaktorα(für Doppelrotation) IHilfskonstruktornode, setzt Größe (l,rbalanciert) ISelektorsizefür Größe des Baumes (0 fürEmpty)

PI3 WS 20/21 35 [44]

Hauptfunktion

Ibalance k x l rkonstruiert balancierten Baum Il,rsind balanciert und höchstens um einen Knoten unbalanciert IVier Fälle:

1 Beide Bäume zusammen höchstens einen Knoten−→keine Rotation 2 w·size(l)<size(r):−→Linksrotation

3 size(l)>w·size(r):−→Rechtsrotation 4 Ansonsten: keine Rotation

IbalanceL k x l rrotiert nach links. Seirlundrrrechter und linker Unterbaum vonr:

1 size(rl)< α·size(rr), dann einfache Linksrotation

2 size(rl)≥α·size(rr) dann Doppelrotation (Rechtsrotationr, dann Linksrotation)

PI3 WS 20/21 36 [44]

Hilfsfunktion join beim Löschen

IZwei balancierte Bäume zusammenfügen (nachdem Wurzel gelöscht wurde) ILinkester Knoten des rechten Unterbaumes wird neue Wurzel

IMitbalancewieder ausbalancieren

join

−−−−−−→

PI3 WS 20/21 37 [44]

Was zum Selbermachen

Übung 8.3: Use the Source, Luke!

Ladet euch von der Webseite der Veranstaltung die Quellen für die 8. Vorlesung herunter, und öffnet die DateiMapTree.hs.

Vergleicht die Haskell-Implementation mit den Beschreibung der Folien.

Welche der Funktionenlookup,insert,deletekönnte man alsfoldrealisieren?

Lösung:lookupläßt sich falten:

lookup’ k=fold (λak ax l r→ ifk==ak thenJust ax elsemaybe r Just l) Nothing

Ist aber nicht so effizient (linear statt logarithmisch), weil es immer erst links, dann rechts sucht.

PI3 WS 20/21 38 [44]

Zusammenfassung Balancierte Bäume

IAuslesen, einfügen und löschen: logarithmischer Aufwand (O(logn))

IFold: linearer Aufwand (O(n))

IGuten durchschnittlicher Aufwand

IAuch in der Haskell-Bücherei:Data.Map(schwer optimiert, mit vielen weiteren Funktionen)

PI3 WS 20/21 39 [44]

Benchmarking: Setup

IWieschnellsind die Implementationenwirklich?

IBenchmarking: nicht trivial

IVerzögerte Auswertung und optimierender Compiler IMessen wir dasrichtige?

IBenchmarking-Tool: Criterion

ISetup:Map Int Stringmit 50000 zufälligen Einträgen erzeugen IDarin:

IEinmal zufällig lesen (lookup), schreiben (insert), löschen (delete) ISequenz aus fünfmal löschen und schreiben, zweihundertmal lesen (mixed)

PI3 WS 20/21 40 [44]

(6)

Benchmarking: Resultate

create lookup insert delete mixed MapFun 333,3 ms

13,58 ms 1,634 ms

52,25µs 11,27 ns

130,8 ps 11,20 ns

120,3 ps 1,659 ms

79,22µs MapList 5,629 s

168,7 ms 32,70µs

9,625µs 96,12µs

1,294µs 101,4µs

18,47µs 6,182 ms

2,059µs MapTree 383,9 ms

19,62 ms 404,1 ns

135,3 ns 119,4µs

13,18µs 117,1µs

42,82µs 2,803 ms

521,5µs Data.Map.Lazy 473,0 ms

44,97 ms 221,6 ns

59,58 ns 104,7µs

49,66µs 112,7µs

11,39µs 2,396 ms

278,8µs

Einträge: durchschnittl. Ausführungszeit, Standardabweichung

PI3 WS 20/21 41 [44]

Defizite von Haskells Modulsystem

ISignatur ist nurimplizit IExportliste enthält nur Bezeichner

IWünschenswert: Signatur an der Exportliste annotierbar, oder Signaturen in separater Datei IIn Java:Interfaces

IKlasseninstanzen werdenimmerexportiert.

IKeinPaket-System

PI3 WS 20/21 42 [44]

Zusammenfassung

IAbstrakte Datentypen(ADTs):

IBesteht ausTypenundOperationendarauf

IRealisierung in Haskell durchModule

IBeispieldatentypen: endliche Abbildungen

INächste Vorlesung: ADTs durchEigenschaftenspezifizieren

PI3 WS 20/21 43 [44]

Frohe Weihnachten und einen Guten Rutsch!

PI3 WS 20/21 44 [44]

Referenzen

ÄHNLICHE DOKUMENTE

Eine Mischung aus 4 - 77% Wasserstoffgas und Sauerstoff wird als Knallgasmischung bezeichnet und reagiert durch einen Funken explosionsartig zu Wasser (bei Raumtemperatur ∆G 0 =

Eine Mischung aus 4 - 77% Wasserstoffgas und Sauerstoff wird als Knallgasmischung bezeichnet und reagiert durch einen Funken explosionsartig zu Wasser (bei Raumtemperatur ΔG 0 =

Für Geld nnd Werthsendungen (Päckchen) ist außer dem Gewichtgeld und der Assecnranzsteuer noch 3 Kop. für die Quittung des Post - ComptoirS über den Empfang deö

gasreichere Mischung zu bekommen, um die Entzündung der ganzen Ladung zu beschleunigen; es ist dies aber auch der einzige Vorteil einer Schichtung der Gase, selbst wenn sich

Hast du eine Erklärung, warum auf dem Bild nur Männer zu sehen sind. Gibt es eine Person, mit der du dich

Wer nicht selbst eine Web- site oder einen Weblog (Web-Tage- buch, in das man Beiträge aller Art hineinschreiben kann) betreibt, postet meist auf einem der grossen sozialen

mehr gibt, sind als Fachbereiche in den neuen Referaten verankert und durch neue Schwerpunkte er- gänzt worden.. 20

- CH: Verordnung über die biologische Landwirtschaft und die Kennzeichnung biologisch produzierter Erzeugnisse und Lebensmittel (seit 2004).. Æ Es braucht