Universit¨at Siegen
Lehrstuhl Theoretische Informatik Carl Philipp Reh
Funktionales Programmieren SS 2020
Ubungsblatt 3¨
Aufgabe 1. Betrachten Sie folgende data-Deklaration:
data E r r o r e a = Fail [ e ] | Ok a
Im Vergleich zu M a y b e benutzen wir hier Fail [ e ] statt N o t h i n g. Die Idee ist, dass [ e ] eine Liste von aufgetretenen Fehlern enth¨alt.
(a) Implementieren Sie die Funktion
s t r i n g T o I n t :: S t r i n g -> E r r o r S t r i n g Int
Diese soll im Fall, dass ein S t r i n g nicht in einen Int konvertieren werden kann, eine geeignete Fehlermeldung als S t r i n g liefern. Zum Konvertieren eines S t r i n g in einen Int k¨onnen Sie die Funktion r e a d M a y b e :: S t r i n g -> M a y b e Int
aus dem Modul Text . Read benutzen. Schreiben Sie hierzu i m p o r t Text . Read ( r e a d M a y b e )
an den Anfang Ihrer Datei.
L¨osung.
s t r i n g T o I n t s = case r e a d M a y b e s of Just x -> Ok x
N o t h i n g -> Fail [ " F a i l e d to c o n v e r t "
++ s ++ " to Int " ]
(b) Implementieren Sie F u n c t o r f¨ur E r r o r e.
L¨osung.
i n s t a n c e F u n c t o r ( E r r o r e ) w h e r e fmap f m = case m of
Fail x -> Fail x Ok x -> Ok ( f x )
(c) Implementieren Sie A p p l i c a t i v e f¨ur E r r o r e. Hierbei sollen alle aufgetretenen Fehler akkumuliert werden. D.h., es soll gelten, dass
1
( Fail x ) <* > ( Fail y ) = Fail ( x ++ y )
L¨osung.
i n s t a n c e A p p l i c a t i v e ( E r r o r e ) w h e r e pure = Ok
f <* > m = case f of Fail x -> case m of
Fail y -> Fail ( x ++ y ) Ok y -> Fail x
Ok g -> case m of Fail y -> Fail y Ok y -> Ok ( g y )
Aufgabe 2. Bei A p p l i c a t i v e hat man die Wahl, <* > oder l i f t A 2 zu implementieren.
(a) Implementieren Sie <* > ¨uber l i f t A 2, was wir a p p l y nennen:
a p p l y :: A p p l i c a t i v e f = >
f ( a -> b ) -> f a -> f b Hinweis: Sie m¨ussen vorher l i f t A 2 importieren:
i m p o r t C o n t r o l . A p p l i c a t i v e ( l i f t A 2 )
L¨osung.
a p p l y f x = l i f t A 2 (\ g y -> g y ) f x
(b) Implementieren Sie l i f t A 2 ¨uber <* >, was wir liftA2 ’ nennen:
liftA2 ’ :: A p p l i c a t i v e f = >
( a -> b -> c ) -> f a -> f b -> f c Hinweis: Sie m¨ussen fmap verwenden.
L¨osung.
liftA2 ’ f x y = ( fmap f ) x <* > y
Aufgabe 3. Man k¨onnte M o n a d auch ¨uber join statt ¨uber > >= imple- mentieren, was allerdings in Haskell nicht vorgesehen ist.
(a) Implementieren Sie join ¨uber > >=, was wir join ’ nennen:
2
join ’ :: M o n a d m = > m ( m a ) -> m a
L¨osung.
join ’ x = x > >= id
Hier ist id :: a -> a die Identit¨atsfunktion.
(b) Implementieren Sie > >= ¨uber join, was wir bind nennen:
bind :: M o n a d m = > m a -> ( a -> m b ) -> m b Hinweis: Sie m¨ussen vorher join importieren:
i m p o r t C o n t r o l . M o n a d ( join ) Sie m¨ussen außerdem fmap verwenden.
L¨osung.
bind x f = join (( fmap f ) x )
Aufgabe 4. Betrachten Sie folgende Data-Deklaration:
data Log a = M k L o g a [ S t r i n g ]
Die Idee von Log ist, dass man neben einem Wert vom Typ a auch noch eine Liste von Log-Meldungen berechnet.
(a) Implementieren Sie F u n c t o r f¨ur Log. L¨osung.
i n s t a n c e F u n c t o r Log w h e r e fmap f x = case x of
( M k L o g y l ) -> M k L o g ( f y ) l
(b) Implementieren Sie A p p l i c a t i v e f¨ur Log. Achten Sie darauf, dass Sie Log-Meldungen akkumulieren m¨ussen.
L¨osung.
i n s t a n c e A p p l i c a t i v e Log w h e r e pure x = M k L o g x []
f <* > x = case f of
( M k L o g f ’ l ) -> case x of
( M k L o g x ’ l ’) -> M k L o g ( f ’ x ’) ( l ++ l ’)
3
(c) Implementieren Sie M o n a d f¨ur Log. Achten Sie darauf, dass Sie Log- Meldungen akkumulieren m¨ussen.
L¨osung.
i n s t a n c e M o n a d Log w h e r e x > >= f = case x of
( M k L o g x ’ l ) -> case f x ’ of
( M k L o g y l ’) -> M k L o g y ( l ++ l ’)
4