diff options
author | Gregor Kleen <gkleen@yggdrasil.li> | 2015-10-31 01:15:59 +0100 |
---|---|---|
committer | Gregor Kleen <gkleen@yggdrasil.li> | 2015-10-31 01:15:59 +0100 |
commit | 4e85d3d65769851e52b03cdaf4df8c210e621246 (patch) | |
tree | c75ea87ac3f5d7e43cebf0eba8486e081d08851c /ws2015/FFP | |
parent | b91812f31131580b751f610164f9c3d24b7c5eaa (diff) | |
download | uni-4e85d3d65769851e52b03cdaf4df8c210e621246.tar uni-4e85d3d65769851e52b03cdaf4df8c210e621246.tar.gz uni-4e85d3d65769851e52b03cdaf4df8c210e621246.tar.bz2 uni-4e85d3d65769851e52b03cdaf4df8c210e621246.tar.xz uni-4e85d3d65769851e52b03cdaf4df8c210e621246.zip |
shortened filenames
Diffstat (limited to 'ws2015/FFP')
-rw-r--r-- | ws2015/FFP/blaetter/02/FFP_U02_Typklassen.hs | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/ws2015/FFP/blaetter/02/FFP_U02_Typklassen.hs b/ws2015/FFP/blaetter/02/FFP_U02_Typklassen.hs new file mode 100644 index 0000000..5f2d936 --- /dev/null +++ b/ws2015/FFP/blaetter/02/FFP_U02_Typklassen.hs | |||
@@ -0,0 +1,206 @@ | |||
1 | -- Fortgeschrittene Funktionale Programmierung, | ||
2 | -- LMU, TCS, Wintersemester 2015/16 | ||
3 | -- Steffen Jost, Alexander Isenko | ||
4 | -- | ||
5 | -- Übungsblatt 02. 28.10.2015 | ||
6 | -- | ||
7 | -- Thema: | ||
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 | -- | A2-1 Funktionsdefinitionen | ||
16 | -- | ||
17 | -- Implementieren Sie folgende grundlegenden, | ||
18 | -- bekannten Funktionen in Haskell. | ||
19 | -- Selbst wenn Sie die Funktion nicht kennen, | ||
20 | -- sollte Ihnen der Typ die korrekte Lösung ermöglichen! | ||
21 | -- | ||
22 | |||
23 | import Prelude hiding (uncurry,flip,(.),map,zip,zipWith,zip,foldl) | ||
24 | |||
25 | import qualified Data.Map as P | ||
26 | |||
27 | -- Hinweis: Das import-Statement müssen Sie jetzt noch nicht verstehen, | ||
28 | -- es ist nur notwendig zur Vermeidung von Namenskonflikten mit der | ||
29 | -- Standardbibliothek, welche die meisten dieser Funktionen bereits enthält. | ||
30 | |||
31 | -- a) Uncurrying | ||
32 | -- > uncurry (/) (1,2) == 0.5 | ||
33 | uncurry :: (a -> b -> c) -> ((a,b) -> c) | ||
34 | uncurry f (a,b) = f a b | ||
35 | |||
36 | -- b) Anwendung einer Funktion mit zwei Argumenten auf ein Paar | ||
37 | -- > (1,2) ||> (/) == 0.5 | ||
38 | (||>) :: (a,b) -> (a -> b -> c) -> c | ||
39 | p ||> f = uncurry f p | ||
40 | |||
41 | |||
42 | -- c) Vertauschung der Reihenfolge der Funktionsargumente | ||
43 | -- > flip (/) 2 1 == 0.5 | ||
44 | flip :: (a -> b -> c) -> (b -> a -> c) | ||
45 | flip f b a = f a b | ||
46 | |||
47 | |||
48 | -- d) Funktionskomposition | ||
49 | -- > ((\x->x+3) . (\y->y*2)) 1 == 5 | ||
50 | (.) :: (b -> c) -> (a -> b) -> a -> c | ||
51 | (.) f g x = f $ g x | ||
52 | |||
53 | |||
54 | -- e) Map (im Gegensatz zu A1-3 dieses Mal ohne List-Comprehension) | ||
55 | -- > map (+10) [1,2,3,4] == [11,12,13,14] | ||
56 | map :: (a -> b) -> [a] -> [b] | ||
57 | map _ [] = [] | ||
58 | map f (x:xs) = f x : map f xs | ||
59 | |||
60 | |||
61 | -- f) zip: | ||
62 | -- > zip ['a','b','c'] [1,2,3,4,5] = [('a',1),('b',2),('c',3)] | ||
63 | zip :: [a] -> [b] -> [(a,b)] | ||
64 | zip [] _ = [] | ||
65 | zip _ [] = [] | ||
66 | zip (x:xs) (y:ys) = (x, y) : zip xs ys | ||
67 | |||
68 | |||
69 | -- g) Zippen mit Funktionsanwendung: | ||
70 | -- > zipWith (+) [1..] [1..3] == [2,4,6] | ||
71 | zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] | ||
72 | zipWith f xs ys = map (uncurry f) $ zip xs ys | ||
73 | |||
74 | |||
75 | -- h) Falten nach links: | ||
76 | -- > foldl (flip (:) ) [] [1..3] == [3,2,1] | ||
77 | -- > foldl (\acc x -> x : acc)) [] [1..3] == [3,2,1] | ||
78 | foldl :: (b -> a -> b) -> b -> [a] -> b | ||
79 | foldl _ x [] = x | ||
80 | foldl f x (y:ys) = foldl f (f x y) ys | ||
81 | |||
82 | |||
83 | |||
84 | -- | A2-2 LambdaTerme | ||
85 | -- | ||
86 | -- Betrachten Sie die Lösung zur A1-1 g): | ||
87 | |||
88 | data LambdaTerm = LVar Char | ||
89 | | LAbs Char LambdaTerm | ||
90 | | LApp LambdaTerm LambdaTerm | ||
91 | |||
92 | -- Ein paar Lambda Terme zum Testen: | ||
93 | lTerm_x = LVar 'x' | ||
94 | lTerm_y = LVar 'y' | ||
95 | lTerm_id = LAbs 'x' lTerm_x | ||
96 | lTerm_xx = LApp lTerm_x lTerm_x | ||
97 | lTerm_t = LAbs 'x' $ LApp lTerm_y lTerm_xx | ||
98 | lTerm_yk = LAbs 'y' $ LApp lTerm_t lTerm_t | ||
99 | |||
100 | -- a) Implementieren Sie eine Eq-Instanz für den Datentyp LambdaTerm! | ||
101 | -- | ||
102 | -- (Wer Lambda-Kalkül kennt: Zur Vereinfachung der Aufgabe | ||
103 | -- ignorieren wir die übliche alpha-Äquivalenz, d.h. | ||
104 | -- (LAbs 'x' $ LVar 'x') und (LAbs 'y' $ LVar 'y') | ||
105 | -- dürfen als verschieden betrachtet werden) | ||
106 | |||
107 | instance Eq LambdaTerm where | ||
108 | (LVar a) == (LVar b) = a == b | ||
109 | (LVar _) == _ = False | ||
110 | (LAbs a t_a) == (LAbs b t_b) = a == b && t_a == t_b | ||
111 | (LAbs _ _) == _ = False | ||
112 | (LApp t_a t'_a) == (LApp t_b t'_b) = t_a == t_b && t'_a == t'_b | ||
113 | (LApp _ _) == _ = False | ||
114 | |||
115 | -- b) Implementieren Sie die eine Show-Instanz für LambdaTerm. | ||
116 | -- Achten Sie dabei auf eine korrekte Klammerung, aber | ||
117 | -- verschwenden Sie erst einmal keine Zeit darauf, | ||
118 | -- überflüssige Klammern zu vermeiden. | ||
119 | |||
120 | instance Show LambdaTerm where | ||
121 | show (LVar a) = "LVar '" ++ pure a ++ "'" | ||
122 | show (LAbs a t) = "LAbs '" ++ pure a ++ "' (" ++ show t ++ ")" | ||
123 | show (LApp t t') = "LApp (" ++ show t ++ ") (" ++ show t' ++ ")" | ||
124 | |||
125 | |||
126 | -- | A2-3 Klassendeklaration | ||
127 | -- | ||
128 | -- a) Deklarieren Sie eine Klasse "FinMap" für endliche partielle Abbildungen, welche folgende Operationen bereitsstellt: | ||
129 | -- 1) "emptyM" liefert eine leere Abbildung | ||
130 | -- 2) "insertM x a m" fügt die Abbildung [x->a] in die Abbildung m ein. | ||
131 | -- Falls x schon enthalten war, dann wird es überschrieben. | ||
132 | -- 3) "lookupM x m" liefert Nothing zurück, falls x nicht in m enthalten ist; | ||
133 | -- ansonsten wird der für x gespeicherte Wert z zurückgeliefert (in Just verpackt) | ||
134 | -- Die Funktion "lookupM" darf dabei annehmen, dass für x eine Vergleichsoperation vorliegt!?! | ||
135 | |||
136 | class FinMap m where | ||
137 | emptyM :: m k v | ||
138 | insertM :: Ord k => k -> v -> m k v -> m k v | ||
139 | lookupM :: Ord k => k -> m k v -> Maybe v | ||
140 | -- Can we get around using constraints here without using the MultiParamTypeClasses language extension? | ||
141 | |||
142 | -- b) Machen Sie folgenden Datentyp zu einer Instanz der Typklasse Map: | ||
143 | |||
144 | -- data AL a b = AL [(a,b)] | ||
145 | newtype AL a b = AL [(a,b)] -- Äquivalent zur vorherigen Zeile. | ||
146 | -- newtype kann und darf verwenden werden, | ||
147 | -- wenn man nur einen Konstruktor mit nur einem Argument hat. | ||
148 | -- Dies erlaubt GHC eine Optimierung durchzuführen. | ||
149 | deriving (Show, Read, Eq) | ||
150 | |||
151 | instance FinMap AL where | ||
152 | emptyM = AL $ [] | ||
153 | insertM x a (AL m) = AL $ (x, a) : [p | p@(x', _) <- m, x' /= x] | ||
154 | lookupM x (AL m) = listToMaybe [y | (x', y) <- m, x' == x] -- Due to lazyness this is no slower than explicitly short-circuiting the search | ||
155 | where | ||
156 | -- This is part of Data.Maybe | ||
157 | listToMaybe [] = Nothing | ||
158 | listToMaybe (x:_) = Just x | ||
159 | |||
160 | |||
161 | ---- Werte zum anschließendem Testen, auskommentieren, | ||
162 | ---- sobald Klasse und Instanz definiert wurden: | ||
163 | testMap0 :: AL Int Bool | ||
164 | testMap0 = emptyM | ||
165 | testMap1 = insertM 1 False testMap0 | ||
166 | testMap2 = insertM 3 False testMap1 | ||
167 | testMap3 = insertM 4 True testMap2 | ||
168 | testMap4 = insertM 2 True testMap3 | ||
169 | |||
170 | |||
171 | -- Hinweis: | ||
172 | -- Partielle Abbildungen wie hier durch Assoziationslisten zu implementieren, | ||
173 | -- ist nicht bensonders effizient, da der Zugriff auf ein Element im Allgemeinen | ||
174 | -- den Aufwand O(n) hat (man muss die ganze Liste abklappern - es könnte sich ja | ||
175 | -- um das letzte Element der Liste handeln). | ||
176 | -- Mit Suchbäumen läßt sich der Aufwand bekanntermaßen auf O(log n) reduzieren. | ||
177 | -- Wer noch Lust & Zeit hat, kann versuchen, dies selbst zu implementieren | ||
178 | -- und zur einer weiteren Instanz von FinMap machen. | ||
179 | -- | ||
180 | -- Die Standardbibliothek sieht zur Abstraktion hier keine solche Klasse vor, | ||
181 | -- sondern bietet lediglich eine konkrete, effiziente Implementierung von | ||
182 | -- endlichen Abbildungen an: Data.Map, welche wir in der kommenden Vorlesung | ||
183 | -- betrachten werden. | ||
184 | -- | ||
185 | -- Dies kann man natürlich ganz schnell zu einer Instanz von FinMap machen. Wie? | ||
186 | |||
187 | data Map k v = Tip | ||
188 | | Branch k v (Map k v) (Map k v) | ||
189 | |||
190 | instance FinMap Map where | ||
191 | emptyM = Tip | ||
192 | insertM k v Tip = Branch k v Tip Tip | ||
193 | insertM k v (Branch k' v' lt gt) | ||
194 | | k == k' = Branch k v lt gt | ||
195 | | k < k' = Branch k' v' (insertM k v lt) gt | ||
196 | | otherwise = Branch k' v' lt (insertM k v gt) | ||
197 | lookupM _ Tip = Nothing | ||
198 | lookupM k (Branch k' v' lt gt) | ||
199 | | k == k' = Just v' | ||
200 | | k < k' = lookupM k lt | ||
201 | | otherwise = lookupM k gt | ||
202 | |||
203 | instance FinMap P.Map where | ||
204 | emptyM = P.empty | ||
205 | insertM = P.insert | ||
206 | lookupM = P.lookup | ||