diff options
-rw-r--r-- | ws2015/ffp/blaetter/05/FFP_U05_ApplikativeF.hs | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/ws2015/ffp/blaetter/05/FFP_U05_ApplikativeF.hs b/ws2015/ffp/blaetter/05/FFP_U05_ApplikativeF.hs new file mode 100644 index 0000000..4f68f18 --- /dev/null +++ b/ws2015/ffp/blaetter/05/FFP_U05_ApplikativeF.hs | |||
@@ -0,0 +1,219 @@ | |||
1 | -- Fortgeschrittene Funktionale Programmierung, | ||
2 | -- LMU, TCS, Wintersemester 2015/16 | ||
3 | -- Steffen Jost, Alexander Isenko | ||
4 | -- | ||
5 | -- Übungsblatt 05. 18.11.2015 | ||
6 | -- | ||
7 | -- Thema: Applikative Funktoren | ||
8 | -- | ||
9 | -- Anweisung: | ||
10 | -- Gehen Sie diese Datei durch und bearbeiten Sie | ||
11 | -- alle Vorkommen von undefined bzw. die mit -- !!! TODO !!! | ||
12 | -- markierten Stellen. Testen Sie Ihre Lösungen mit GHCi! | ||
13 | -- | ||
14 | -- _____________________________________________________________________ | ||
15 | -- | | | ||
16 | -- | Ziele für dieses Blatt: | | ||
17 | -- | * Instanzen für eigene Datentypen schreiben können | | ||
18 | -- | * Applicative Gesetze und Klassenfunktionen kennenlernen | | ||
19 | -- | * Klasse Traversable kennenlernen | | ||
20 | -- |_____________________________________________________________________| | ||
21 | -- | | ||
22 | -- λ_/ | ||
23 | -- /| | ||
24 | -- / \ | ||
25 | |||
26 | import Prelude hiding (Traversable, traverse) | ||
27 | import Data.Functor | ||
28 | import Control.Applicative | ||
29 | |||
30 | ---- A5-1 Instanzen von Applikativen Funktoren | ||
31 | -- | ||
32 | -- Gegeben ist eine alternative Datentypdeklaration | ||
33 | -- für gewöhnliche Listen: | ||
34 | |||
35 | data List a = Nil | Cons a (List a) | ||
36 | deriving (Eq, Show) | ||
37 | |||
38 | {- | ||
39 | -- Manuell definierte Show-Instanz für gewöhnliche Schreibweise: | ||
40 | instance Show a => Show (List a) where | ||
41 | show Nil = "[]" | ||
42 | show (Cons x Nil) = show x ++ " : " ++ "[]" | ||
43 | show (Cons x xs) = show x ++ " : " ++ show xs | ||
44 | -- | ||
45 | -- Für den Ausdruck gilt damit folgende Schreibweise: | ||
46 | -- [] entspricht Nil | ||
47 | -- (h:t) entspricht (Cons h t) | ||
48 | -} | ||
49 | |||
50 | |||
51 | -- In der Vorlesung wurden zwei Möglichkeiten vorgestellt, | ||
52 | -- Listen zu Applikativen Funktoren zu machen. | ||
53 | -- In dieser Aufgabe sollen Sie dies nachvollziehen, | ||
54 | -- d.h. schauen Sie dabei also möglichst _NICHT_ in Folien 4-19 ff. | ||
55 | -- sondern nur die davor! | ||
56 | |||
57 | |||
58 | -- a) Betrachten Sie folgenden fehlerhaften Lösungsversuch. | ||
59 | -- Der Lösungsversuch kompiliert und lässt sich ausführen, | ||
60 | -- aber die Gesetze eines Applikativen Funktors werden | ||
61 | -- missachtet. | ||
62 | -- Finden Sie durch ausprobieren mindestens ein Gesetz, | ||
63 | -- welches missachtet wird! | ||
64 | -- | ||
65 | -- Beispiel: | ||
66 | -- > pure id <*> Nil2 :: List2 Int -- explizite Typangabe | ||
67 | -- Nil2 | ||
68 | -- liefert noch keinen Hinweis daruf, dass z.B. das Gesetz "Identität" | ||
69 | -- verletzt wird -- aber vielleicht wird es für andere Werte als Nil2 verletzt, | ||
70 | -- oder vielleicht wird ein anderes Gesetz verletzt?! Finden Sie es heraus! | ||
71 | -- | ||
72 | -- Hinweis: Achten Sie bei Ihren Tests in GHCI darauf, | ||
73 | -- dass auch die richtige Instanz verwendet wird, | ||
74 | -- z.B. durch explizite Angabe des Typs! | ||
75 | |||
76 | data List2 a = Nil2 | Cons2 a (List2 a) deriving (Show, Eq) | ||
77 | |||
78 | instance Functor List2 where | ||
79 | fmap _ Nil2 = Nil2 | ||
80 | fmap f (Cons2 x xs) = Cons2 (f x) (fmap f xs) | ||
81 | |||
82 | instance Applicative List2 where | ||
83 | -- pure :: a -> List2 a -- Typsignaturen sind in Instanzdeklarationen unzulässig | ||
84 | pure x = Nil2 | ||
85 | -- <*> :: List2 (a -> b) -> List2 a -> List2 b | ||
86 | Nil2 <*> _ = Nil2 | ||
87 | (Cons2 x xs) <*> Nil2 = Nil2 | ||
88 | (Cons2 x xs) <*> Cons2 y ys = Cons2 (x y) (xs <*> ys) | ||
89 | |||
90 | {- | ||
91 | - Nimm: | ||
92 | - ghci> pure id <*> (Cons2 () Nil2) | ||
93 | - Nil2 | ||
94 | - Dies verletzt Identität. | ||
95 | -} | ||
96 | |||
97 | -- b) Ist folgende Nachbesserung zur a) wirklich besser? | ||
98 | -- Werden nun alle Gesetze respektiert? | ||
99 | |||
100 | data List3 a = Nil3 | Cons3 a (List3 a) deriving (Show, Eq) | ||
101 | |||
102 | instance Functor List3 where | ||
103 | fmap f xs = pure f <*> xs | ||
104 | |||
105 | instance Applicative List3 where | ||
106 | -- pure :: a -> List3 a | ||
107 | pure x = Cons3 x Nil3 | ||
108 | -- <*> :: List3 (a -> b) -> List3 a -> List3 b | ||
109 | Nil3 <*> _ = Nil3 | ||
110 | (Cons3 x xs) <*> Nil3 = Nil3 | ||
111 | (Cons3 x xs) <*> Cons3 y ys = | ||
112 | Cons3 (x y) (xs <*> ys) | ||
113 | |||
114 | {- | ||
115 | - Nimm: | ||
116 | - ghci> pure id <*> (Cons3 () (Cons3 () Nil3)) | ||
117 | - Cons3 () Nil3 | ||
118 | - Auch dies verletzt Identität. | ||
119 | -} | ||
120 | |||
121 | -- c) Machen Sie es nun selbst richtig! | ||
122 | -- Machen Sie den Typ List zu einer korrekten Instanz von Applicative! | ||
123 | -- Experimentieren Sie anschliessend mit ein paar Beispielen. | ||
124 | |||
125 | instance Functor List where | ||
126 | fmap f xs = pure f <*> xs | ||
127 | |||
128 | -- Analog zu ZipList | ||
129 | instance Applicative List where | ||
130 | pure x = Cons x (pure x) | ||
131 | (Cons x xs) <*> (Cons y ys) = Cons (x y) (xs <*> ys) | ||
132 | _ <*> _ = Nil | ||
133 | |||
134 | |||
135 | ---- A5-2 Kontextfolge | ||
136 | -- | ||
137 | -- Gegeben ist folgende Funktionsdefinition, | ||
138 | -- bei der leider die Typsignatur fehlt. | ||
139 | |||
140 | -- a) | ||
141 | -- Berechnen Sie die Typsignatur selbst manuell, also ohne einfach GHCI zu fragen! | ||
142 | -- Schlagen Sie ggf. die Typen von pure, (:), (<$>) und (<*>) nach! | ||
143 | |||
144 | folgeA :: Applicative f => [f a] -> f [a] | ||
145 | folgeA [] = pure [] | ||
146 | folgeA (h:t) = (:) <$> h <*> folgeA t | ||
147 | |||
148 | |||
149 | -- b) | ||
150 | -- Wieder eine Denksportaufgabe: | ||
151 | -- zu welchem Ergebnis wertet folgende Ausdrücke aus: | ||
152 | |||
153 | a5_2b1 = folgeA [Just 1, Just 27, Just 2] | ||
154 | -- Just [1, 27, 2] | ||
155 | a5_2b2 = folgeA [Just 4, Just (sqrt 27), Just (sum [1..100]), Nothing, Just 0] | ||
156 | -- Nothing | ||
157 | a5_2b3 = folgeA [[1,2],[3],[4,5]] | ||
158 | -- [[1,3,4],[1,3,5],[2,3,4],[2,3,5]] | ||
159 | a5_2b4 = folgeA [ZipList [1,2], ZipList [3], ZipList [4,5]] | ||
160 | -- ZipList [1, 3, 4] | ||
161 | a5_2b5 = folgeA [(*2),(+1), negate] $ 3 | ||
162 | -- [6, 4, -3] | ||
163 | |||
164 | |||
165 | |||
166 | |||
167 | ---- A5-3 Anwendung von Applikativen Funktoren mit der Typklasse Traversable | ||
168 | -- | ||
169 | -- | ||
170 | -- Gegeben ist folgende vereinfachte Version | ||
171 | -- der Typklasse Traversable (im Original siehe Modul Data.Traversable: | ||
172 | -- | ||
173 | |||
174 | class Traversable t where | ||
175 | traverse :: Applicative f => (a -> f b) -> t a -> f (t b) | ||
176 | |||
177 | sequenceA :: Applicative f => t (f a) -> f (t a) | ||
178 | sequenceA = traverse id | ||
179 | |||
180 | |||
181 | -- Weiterhin ist folgender Datentyp für Binäre Bäume gegeben: | ||
182 | |||
183 | data Baum a = Blatt a | Gabel (Baum a) a (Baum a) | Astloch | ||
184 | deriving (Show, Eq) | ||
185 | |||
186 | test1 = Gabel (Blatt 42) 1 (Gabel (Gabel Astloch 69 $ Blatt 7) 44 Astloch) | ||
187 | test2 = Gabel (Blatt [42]) [1,2,3] (Gabel (Gabel Astloch [69,96] $ Blatt [7]) [44,101,0] Astloch) | ||
188 | |||
189 | |||
190 | -- a) Machen Sie den Typ "Baum" zu einer Instanz | ||
191 | -- der Tyklasse Traversable! | ||
192 | -- | ||
193 | -- Hinweis: | ||
194 | -- Schauen Sie sich _NICHT_ das Modul Data.Traversable | ||
195 | -- aus der Standardbibliothek an, da dessen Dokumentation | ||
196 | -- bereits die Lösung zu dieser Aufgabe als Beispiel behandelt. | ||
197 | |||
198 | instance Traversable Baum where | ||
199 | traverse _ Astloch = pure Astloch | ||
200 | traverse f (Blatt x) = Blatt <$> f x | ||
201 | traverse f (Gabel c1 x c2) = Gabel <$> traverse f c1 <*> f x <*> traverse f c2 | ||
202 | |||
203 | -- Beispiele: | ||
204 | -- > take 1 $ drop 4 $ traverse (\x->[x,-x]) test1 | ||
205 | -- [Gabel (Blatt 42) 1 (Gabel (Gabel Astloch (-69) (Blatt 7)) 44 Astloch)] | ||
206 | -- | ||
207 | -- > traverse (\x->if x>0 then Just x else Nothing) test1 | ||
208 | -- Just (Gabel (Blatt 42) 1 (Gabel (Gabel Astloch 69 (Blatt 7)) 44 Astloch)) | ||
209 | -- | ||
210 | -- > traverse (\x->if even x then Just x else Nothing) test1 | ||
211 | -- Nothing | ||
212 | -- | ||
213 | -- > take 2 $ drop 5 $ sequenceA test2 | ||
214 | -- [Gabel (Blatt 42) 1 (Gabel (Gabel Astloch 96 (Blatt 7)) 0 Astloch),Gabel (Blatt 42) 2 (Gabel (Gabel Astloch 69 (Blatt 7)) 44 Astloch)] | ||
215 | |||
216 | |||
217 | -- b) Gibt es einen Zusammenhang zwischen folgeA und sequenceA? | ||
218 | |||
219 | -- folgeA ist sequenceA spezialisiert auf [] | ||