diff options
| author | Gregor Kleen <gkleen@yggdrasil.li> | 2015-11-18 16:50:48 +0100 |
|---|---|---|
| committer | Gregor Kleen <gkleen@yggdrasil.li> | 2015-11-18 16:50:48 +0100 |
| commit | 17af38d7b43fbb8d2105de5e01fe27795a724119 (patch) | |
| tree | 64bd7e24996d5f7e2eabdfc82df285926a9cf866 | |
| parent | dc30f414e08e3df442824b4e4fb57b8ae4f14b18 (diff) | |
| download | uni-17af38d7b43fbb8d2105de5e01fe27795a724119.tar uni-17af38d7b43fbb8d2105de5e01fe27795a724119.tar.gz uni-17af38d7b43fbb8d2105de5e01fe27795a724119.tar.bz2 uni-17af38d7b43fbb8d2105de5e01fe27795a724119.tar.xz uni-17af38d7b43fbb8d2105de5e01fe27795a724119.zip | |
FFP - 05
| -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 [] | ||
