• Keine Ergebnisse gefunden

Funktionales Programmieren Teil 3 Carl Philipp Reh

N/A
N/A
Protected

Academic year: 2021

Aktie "Funktionales Programmieren Teil 3 Carl Philipp Reh"

Copied!
13
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Funktionales Programmieren

Teil 3

Carl Philipp Reh

Universit¨at Siegen

22. Mai 2020

(2)

Functor

Die Funktion map :: ( a - > b ) - > [ a ] - > [ b ]

bekommt eine Funktion f :: a - > b und wendet diese auf alle Elemente einer Liste an. Zum Beispiel gilt

map s h o w [1 ,2] = [ " 1 " , " 2 " ]

map (\ x - > mod x 2 == 0) [1 ,2 ,3]

= [ False , True , F a l s e ]

Dies funktioniert nicht bloß auf Listen, sondern auf vielen verschiedenen Datenstrukturen, die Elemente

”enthalten“. Hierf¨ur hat Haskell eine eigene Typklasse:

c l a s s F u n c t o r f w h e r e

f m a p :: ( a - > b ) - > f a - > f b

Die Implementierung f¨ur Listen ist:

i n s t a n c e F u n c t o r [] w h e r e f m a p = map

(3)

Functor

c l a s s F u n c t o r f w h e r e

f m a p :: ( a - > b ) - > f a - > f b

Da hier f a und f b gebildet werden, muss f :: * - > * gelten, was zum Beispiel passend ist f¨ur [ ] : : * - > *.

Ein Functor ist also ein Typkonstruktor mit Kind * - > *, d.h.

eine Abbildung von Typen auf Typen, und eine Funktion, die Funktionen vom Typ a - > b auf Funktionen vom Typ f a - > f b abbildet.

(4)

Functor

c l a s s F u n c t o r f w h e r e

f m a p :: ( a - > b ) - > f a - > f b Beispielsweise sieht die Implementierung f¨ur M a y b e folgendermaßen aus:

i n s t a n c e F u n c t o r M a y b e w h e r e f m a p f m = c a s e m of

N o t h i n g - > N o t h i n g J u s t x - > J u s t ( f x )

Zum Beispiel gilt

f m a p (\ x - > x + 1) N o t h i n g = N o t h i n g f m a p (\ x - > x + 1) ( J u s t 3) = J u s t 4

(5)

Functor

Anwendungsbeispiel: Wir wollen ausrechnen, ob ein Benutzer vollj¨ahrig ist. Dieser gibt sein Alter als String ein, den wir erst umwandeln m¨ussen mit der Funktion

s t r i n g T o I n t :: S t r i n g - > M a y b e Int

Diese gibt N o t h i n g zur¨uck, wenn der String kein g¨ultiger Int ist. Zum Testen, ob jemand mindestens 18 ist, definieren wir i s A d u l t :: Int - > B o o l

i s A d u l t x = x >= 18

Dann gilt zum Beispiel

f m a p i s A d u l t ( s t r i n g T o I n t " abc " ) = N o t h i n g f m a p i s A d u l t ( s t r i n g T o I n t " 10 " ) = J u s t F a l s e f m a p i s A d u l t ( s t r i n g T o I n t " 20 " ) = J u s t T r u e

(6)

Applicative

A p p l i c a t i v e ist eine Erweiterung von F u n c t o r, die es erlaubt, ¨uber mehr als einen Wert auf einmal zu

”mappen“. Als Beispiel wollen wir ausgeben, ob ein Benutzer ¨alter ist als der andere. Dazu definieren wir

i s O l d e r T h a n :: Int - > Int - > B o o l

Mit f m a p auf M a y b e erhalten wir f m a p i s O l d e r T h a n

:: M a y b e Int - > M a y b e ( Int - > B o o l )

Um damit weiter zu arbeiten, brauchen wir eine Funktion M a y b e ( Int - > B o o l ) - > M a y b e Int

- > M a y b e B o o l die uns von A p p l i c a t i v e bereitgestellt wird:

( <* >) :: f ( a - > b ) - > f a - > f b

(7)

Applicative

Die volle Definition von A p p l i c a t i v e ist

c l a s s F u n c t o r f = > A p p l i c a t i v e f w h e r e p u r e :: a - > f a

( <* >) :: f ( a - > b ) - > f a - > f b Die Funktion p u r e

”bettet einen Wert ein“.

Die Implementierung f¨ur M a y b e sieht folgendermaßen aus i n s t a n c e A p p l i c a t i v e M a y b e w h e r e

p u r e = J u s t

f <* > m = c a s e f of N o t h i n g - > N o t h i n g J u s t f ’ - > c a s e m of

N o t h i n g - > N o t h i n g

J u s t m ’ - > J u s t ( f ’ m ’)

Es gilt also f¨ur g :: a - > b und x :: a, dass J u s t g <* > J u s t x = J u s t ( g x )

(8)

Applicative

Wir k¨onnen in unserem Beispiel dann schreiben:

c o m p a r e A g e s ::

S t r i n g - > S t r i n g - > M a y b e B o o l c o m p a r e A g e s x y =

( f m a p i s O l d e r T h a n ) ( s t r i n g T o I n t x )

<* > ( s t r i n g T o I n t y )

Um diesen Code besser zu verstehen, ist es wichtig, sich die Typen, die auftreten, anzuschauen: Zun¨achst haben wir, dass

f m a p i s O l d e r T h a n ::

M a y b e Int - > M a y b e ( Int - > B o o l ) Dieses wenden wir dann auf

s t r i n g T o I n t x :: M a y b e Int an und erhalten M a y b e ( Int - > B o o l ). Als N¨achstes ¨ubergeben wir dies zusammen mit s t r i n g T o I n t y :: M a y b e Int an <* >

und erhalten M a y b e B o o l.

(9)

Applicative

A p p l i c a t i v e erlaubt es, statt <* > die Funktion l i f t A 2 zu implementieren:

l i f t A 2 :: ( a - > b - > c ) - > f a - > f b - > f c

Als Beispiel betrachten wir wieder M a y b e: i n s t a n c e A p p l i c a t i v e M a y b e w h e r e

l i f t A 2 f m m ’ = c a s e m of N o t h i n g - > N o t h i n g

J u s t x - > c a s e m ’ of N o t h i n g - > N o t h i n g

J u s t x ’ - > J u s t ( f x x ’)

Wir k¨onnen dann auch schreiben c o m p a r e A g e s x y =

l i f t A 2 i s O l d e r T h a n

( s t r i n g T o I n t x ) ( s t r i n g T o I n t y )

(10)

Applicative

Als Anwendungsbeispiel von A p p l i c a t i v e betrachten wir die Funktion s e q u e n c e A auf Listen:

s e q u e n c e A :: A p p l i c a t i v e f = > [ f a ] - > f [ a ]

Mit M a y b e ergibt sich

s e q u e n c e A :: [ M a y b e a ] - > M a y b e [ a ]

Hierbei gilt, dass s e q u e n c e A l = N o t h i n g genau dann, wenn mindestens ein Element inl N o t h i n g ist.

Beispielsweise gilt

s e q u e n c e A [ Nothing , J u s t 1] = N o t h i n g s e q u e n c e A [ J u s t 1 , J u s t 2] = J u s t [1 ,2]

Wichtig: Die Implementierung von s e q u e n c e A auf Listen funktioniert mit jedem A p p l i c a t i v e.

(11)

Monad

M o n a d ist eine Erweiterung von A p p l i c a t i v e, die es erlaubt,

”sequentielle Abh¨angigkeit“ auszudr¨ucken.

Als Beispiel wollen wir die Fehlerbehandlung beim Einlesen eines Alters erweitern. Wir wollen Int durch Nat ersetzen, sodass das Alter nicht mehr negativ sein kann. Zum Konvertieren von Int zu Nat verwenden wir die Funktion

i n t T o N a t :: Int - > M a y b e Nat

Die Funktion s t r i n g T o I n t liefert uns M a y b e Int. Dieses wollen wir nur an i n t T o N a t ¨ubergeben, wenn es nicht N o t h i n g ist. Wir brauchen also eine Funktion

M a y b e Int - > ( Int - > M a y b e Nat ) - > M a y b e Nat Diese wird uns von M o n a d bereitgestellt:

( > >=) :: f a - > ( a - > f b ) - > f b

(12)

Monad

Die allgemeine Definition von M o n a d ist

c l a s s A p p l i c a t i v e f = > M o n a d f w h e r e ( > >=) :: f a - > ( a - > f b ) - > f b Zum Beispiel sieht die Implementierung von M a y b e so aus:

i n s t a n c e M o n a d M a y b e w h e r e m > >= f = c a s e m of

N o t h i n g - > N o t h i n g J u s t x - > f x

Die Funktion fkann nur einen Wert produzieren, wenn m schon nicht N o t h i n g ist. Diese

”sequentielle Abh¨angigkeit“ kann man nicht mit A p p l i c a t i v e alleine ausdr¨ucken. Zum Beispiel gilt:

s t r i n g T o I n t " x " > >= i n t T o N a t = N o t h i n g s t r i n g T o I n t " -5 " > >= i n t T o N a t = N o t h i n g s t r i n g T o I n t " 2 " > >= i n t T o N a t

= J u s t ( S u c c ( S u c c Z e r o ) )

(13)

Monad

Als Anwendungsbeispiel von M o n a d betrachten wir die Funktion j o i n :: M o n a d f = > f ( f a ) - > f a

Diese

”entfernt“ eine Schicht eines Typkonstruktors. Zum Beispiel erhalten wir f¨ur M a y b e und [], dass

j o i n ( J u s t ( J u s t 10) ) = J u s t 10 j o i n ( J u s t N o t h i n g ) = N o t h i n g j o i n [ [ ] ] = []

j o i n [[1 ,2] ,[] ,[3 ,4] ,[5]] = [1 ,2 ,3 ,4 ,5]

Auch hier gilt nat¨urlich, dass j o i n mit jeder Monade funktioniert.

Referenzen

ÄHNLICHE DOKUMENTE

Er besagt, dass jede stetige Funktion einen kleinsten Fixpunkt hat und zeigt sogar, wie man diesen erh¨ alt..

Allerdings terminiert g c nicht, weil es sein Argument so weit auswerten muss, bis klar ist, welcher Wertkonstruktor (hier M a k e ) angewandt wurde. Wir ben¨ otigen also nicht

Wir werden hierbei einige Einschr¨ ankungen vornehmen, die allerdings keine wirklichen Einschr¨ ankungen sind, da man alle anderen Haskell-Programme in unsere erlaubte Syntax

Wir m¨ ussten eigentlich noch zeigen, dass alle Funktionen, die wir in der Definition der Semantik benutzt haben, auch stetig sind.. Da dies allerdings sehr aufw¨ andig ist, m¨

Intuitiv geschieht dies, indem man Typvariablen so ersetzt, dass alle Typgleichungen von der Form τ = τ sind, also zum Beispiel α = Int wird zu Int = Int, indem man α durch

I ” nicht l¨ osbar“ liefert, wenn es keine L¨ osung f¨ ur E gibt, I und andernfalls eine allgemeinste L¨ osung f¨ ur E liefert.. Wir starten mit einer Substitution s, die am

Lehrstuhl Theoretische Informatik Carl Philipp Reh. Funktionales Programmieren

Lehrstuhl Theoretische Informatik Carl Philipp Reh. Funktionales Programmieren