summaryrefslogtreecommitdiff
path: root/ws2015
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2015-11-24 14:29:20 +0100
committerGregor Kleen <gkleen@yggdrasil.li>2015-11-24 14:29:20 +0100
commit76b9e428426e2afeb67f48c094bbc0225563dd3d (patch)
tree0c10c68b5963a8e11724cba86879d4c395a7ab4b /ws2015
parent154ed6744254b0d7553e40071656b53382816123 (diff)
downloaduni-76b9e428426e2afeb67f48c094bbc0225563dd3d.tar
uni-76b9e428426e2afeb67f48c094bbc0225563dd3d.tar.gz
uni-76b9e428426e2afeb67f48c094bbc0225563dd3d.tar.bz2
uni-76b9e428426e2afeb67f48c094bbc0225563dd3d.tar.xz
uni-76b9e428426e2afeb67f48c094bbc0225563dd3d.zip
FFP - 06 (partially) & 06b
Diffstat (limited to 'ws2015')
-rw-r--r--ws2015/ffp/blaetter/06/FFP_U06_Monaden.hs193
-rw-r--r--ws2015/ffp/blaetter/06/FFP_U06b_ApplParse.hs256
2 files changed, 449 insertions, 0 deletions
diff --git a/ws2015/ffp/blaetter/06/FFP_U06_Monaden.hs b/ws2015/ffp/blaetter/06/FFP_U06_Monaden.hs
new file mode 100644
index 0000000..f444ad0
--- /dev/null
+++ b/ws2015/ffp/blaetter/06/FFP_U06_Monaden.hs
@@ -0,0 +1,193 @@
1-- Fortgeschrittene Funktionale Programmierung,
2-- LMU, TCS, Wintersemester 2015/16
3-- Steffen Jost, Alexander Isenko
4--
5-- Übungsblatt 06a. 25.11.2015
6--
7-- Thema: Monaden-Gesetze, Erste Schritte mit Monaden und Do-Notation
8--
9-- Hier machen wir ein paar erste Schritte mit Monaden.
10-- Wer das alles schon kennt und bereits von woanders her
11-- mit der Do-Notation vertraut ist, sollte stattessen
12-- die B-Version dieses Übungsblattes machen:
13-- einen applikativen Parser bauen.
14--
15-- Gehen Sie diese Datei durch und bearbeiten Sie
16-- alle Vorkommen von undefined bzw. die mit -- !!! TODO !!!
17-- markierten Stellen. Testen Sie Ihre Lösungen mit GHCi!
18
19
20---- A6-1 Monaden Gesetze nachweisen
21--
22--
23-- a)
24-- Auf Folie 04-42 fehlt der Beweis für die Assoziativität
25-- Maybe-Instanz für die Typklasse Monad.
26-- Führen Sie den Beweis aus!
27-- (Geht ganz analog zu den anderen beiden Beweisen, d.h.
28-- Definitionen ausfalten und umformen.
29-- Bei Abgabe: Bitte zusätzlich kurze Begründung für jeden Schritt angeben!)
30{-
31Zu Zeigen:
32 Ausdruck
33 m >>= (\x-> ((f x) >>= g))
34 ist gleich zu
35 (m >>= f) >>= g
36-}
37
38-- !!! TODO !!!
39
40
41-- b)
42{- Beweisen Sie, dass folgende Definition
43
44 instance Monad [] where
45 return x = [x] -- (Mo1)
46 xs >>= f = concat (map f xs) -- (Mo2)
47
48 das Monaden-Gesetz "Links-Identität" einhält!
49
50 Folgende Definition sind dabei eventuell nützlich:
51
52 concat :: [[a]] -> [a]
53 concat [] = [] -- (CcN)
54 concat (xs:xss) = xs ++ concat xss -- (CcC)
55
56 (++) :: [a] -> [a] -> [a]
57 (++) xs [] = xs -- (ANr)
58 (++) [] ys = ys -- (ANl)
59 (++) (x:xs) ys = x : (xs ++ ys) -- (ACl)
60
61 map :: (a -> b) -> [a] -> [b]
62 map _ [] = -- (MpN)
63 map f (x:xs) = (f x) : (map f xs) -- (MpC)
64-}
65
66-- !!! TODO !!!
67
68
69
70
71---- A6-2 Either-Monade und Do-Notation
72--
73-- In der vorletzten Vorlesung am 12.11. haben wir gesehen
74-- wie der Datentyp Either der Standardbibliothek zum
75-- Funktor gemacht werden kann.
76--
77-- Machen Sie diesen Datentyp nun zu einer Monade!
78-- Um Namenskonflikten aus dem Weg zu gehen,
79-- definieren wir Either einfach noch mal neu:
80
81data Entweder a b = Eines a | Anderes b
82 deriving (Show, Eq)
83
84-- Die Idee ist dabei die gleiche wie bei Maybe,
85-- nur das "Nothing" hier noch einen Wert tragen kann.
86
87instance Functor (Entweder a) where
88 fmap f (Anderes x) = Anderes $ f x
89 fmap _ (Eines x) = Eines x -- Because x@(Either a b) is not (Either a c), even if we can prove that x is Left.
90
91instance Applicative (Entweder a) where
92 pure = Anderes
93 (Anderes f) <*> (Anderes x) = Anderes $ f x
94 (Eines x) <*> _ = Eines x -- ditto
95 _ <*> (Eines x) = Eines x
96
97instance Monad (Entweder a) where
98 (Anderes a) >>= f = f a
99 (Eines x) >>= _ = Eines x -- ditto
100
101-- Applicative Tests:
102-- (*) <$> (Anderes 3) <*> (Anderes 4)
103-- (*) <$> (Eines 3) <*> (Anderes 4)
104-- (*) <$> (Anderes 3) <*> (Eines 4)
105
106
107-- b)
108-- Verallgemeinern Sie folgende gewöhnlichen Funktionsdefinition,
109-- welche Kenntnis des Typs Entweder voraussetzen.
110-- Schreiben Sie jeweils eine generische Fassung,
111-- welche nur die Monaden-Instanz oder, wenn möglich,
112-- nur Applicative voraussetzt:
113
114-- b1) Beispiel:
115multEnt :: (Num b) => (Entweder a b) -> (Entweder a b) -> (Entweder a b)
116multEnt (Anderes x) (Anderes y) = Anderes (x * y)
117multEnt (Anderes _) other = other
118multEnt other _ = other
119
120
121multEnt_M :: (Num b, Monad m) => m b -> m b -> m b
122multEnt_M = multEnt_A -- The monad-applicative proposal was implemented ;-)
123
124multEnt_A :: (Num b, Applicative f) => f b -> f b -> f b
125multEnt_A a b = (*) <$> a <*> b
126
127
128-- b2)
129foo :: (Entweder a (b->c)) -> (Entweder a b) -> (Entweder a c)
130foo (Anderes f) (Anderes x) = Anderes $ f x
131foo (Eines a) _ = Eines a
132foo _ (Eines a) = Eines a
133
134foo_M :: (Monad m) => (m (b->c)) -> (m b) -> (m c)
135foo_M = foo_A
136
137foo_A :: (Applicative m) => (m (b->c)) -> (m b) -> (m c)
138foo_A f x = ($) <$> f <*> x
139
140
141-- b3)
142ifM :: (Entweder a Bool) -> (Entweder a b) -> (Entweder a b) -> (Entweder a b)
143ifM (Anderes True) x _ = x
144ifM (Anderes False) _ y = y
145ifM (Eines a) _ _ = Eines a
146
147ifM_M :: (Monad m) => m Bool -> m b -> m b -> m b
148ifM_M = ifM_A
149ifM_A :: (Applicative f) => f Bool -> f b -> f b -> f b
150ifM_A b x y = bool <$> x <*> y <*> b
151
152
153
154bool :: a -> a -> Bool -> a
155-- ^ This should really be in Prelude (Data.Bool at least)
156bool x _ True = x
157bool _ x False = x
158
159
160
161---- A6-3 Do - Notation
162--
163-- Implementieren Sie folgende Funktion unter Verwendung der Do-Notation:
164-- Hinweis: Einfach den Typen folgen, alles andere kommt von allein!
165
166filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
167filterM p = foldr trav (return [])
168 where
169 trav x xs = bool (x :) id <$> p x <*> xs -- Applicative is cooler than do notation ;-)
170
171 trav' x xs = do -- But if I must …
172 include <- p x
173 xs' <- xs
174 return $ case include of
175 True -> x : xs'
176 False -> xs'
177
178-- Beispiele zum Testen:
179silly1 :: Int -> Maybe Bool
180silly1 0 = Nothing
181silly1 x = Just $ even x
182
183silly2 :: Int -> [Bool]
184silly2 0 = []
185silly2 x | even x = [False,True,True,False]
186 | otherwise = [False,False]
187
188-- > filterM silly [1..10]
189-- Just [2,4,6,8,10]
190
191-- > filterM silly $ [1..10]++[1,0,1]
192-- Nothing
193
diff --git a/ws2015/ffp/blaetter/06/FFP_U06b_ApplParse.hs b/ws2015/ffp/blaetter/06/FFP_U06b_ApplParse.hs
new file mode 100644
index 0000000..b63e800
--- /dev/null
+++ b/ws2015/ffp/blaetter/06/FFP_U06b_ApplParse.hs
@@ -0,0 +1,256 @@
1-- Fortgeschrittene Funktionale Programmierung,
2-- LMU, TCS, Wintersemester 2015/16
3-- Steffen Jost, Alexander Isenko
4--
5-- Übungsblatt 06b. 25.11.2015
6--
7-- Thema: Applikativer Parser
8--
9-- Als Beispiel betrachten wir hier einen primitiven applikativen Parser.
10-- Alles wesentliche liegt in dieser Datei vor.
11-- Dies hat den Nachteil, dass es die Datei aufbläht;
12-- aber auch den Vorteil, dass man genau sehen kann wie alles funktioniert.
13-- Also nicht abschrecken lassen, Ihr müsst hier nicht alle Details verstehen!
14--
15-- Die Funktionen orientieren sich an den Modulen Text.Parsec
16-- und Text.ParserCombinators.ReadP welche zwei verschiedene
17-- monadische Parser zur Verfügung stellen, d.h. dieses Beispiel
18-- könnte man auch tatsächlich nutzen, um einen richtigen Parser zu schreiben.
19-- Beide Module setzen jedoch entgegen der vereinfachten Version hier
20-- eine volle Monade ein, anstatt lediglich einen applikativen
21-- Funktor zu verwenden, welcher auch ausreicht!
22--
23-- Aufgabenstellung folgt in Zeile 169
24--
25
26import Data.Maybe
27import Data.Char as Char
28import Data.Functor
29import Control.Applicative
30import Data.Traversable
31
32-- newtype eines Parser wird für Instanzdeklarationen benötigt
33newtype Parser a = Parser (String -> [(a,String)])
34
35runParser :: Parser a -> String -> [(a,String)]
36runParser (Parser p) s = p s
37
38runParserComplete :: Parser a -> String -> [a]
39runParserComplete (Parser p) s = [ r |(r,"") <- p s]
40
41parse :: Parser a -> String -> Maybe a -- returns first complete parse
42parse p s = listToMaybe $ runParserComplete p s
43
44-- Die Instanzdeklarationen
45instance Functor Parser where
46 fmap f (Parser p) = Parser $ \s -> map (\(a,b) -> (f a, b)) $ p s
47
48instance Applicative Parser where
49 -- pure :: a -> Parser a -- konsumiert keine Eingabe und liefer immer ein Ergebnis
50 pure x = Parser $ \s -> [(x,s)]
51
52 -- <*> :: Parser (a -> b) -> Parser a -> Parser b -- parsed eine Funktion und aus dem Rest der Eingabe ein Argument für diese Funktion und liefert das Ergebnis
53 (Parser p1) <*> (Parser p2) = Parser $ \inp ->
54 [(r1 r2, rem2) | (r1,rem1) <- p1 inp, (r2,rem2) <- p2 rem1]
55
56-- Ebenfalls in Modul Control.Applicative definiert:
57-- Typklasse Alternative ist eine Unterklasse für Applikative Funktoren
58-- mit Monoid-Strultur, d.h.: es gibt eine binäre Verküpfung mit neutralem Element!
59instance Alternative Parser where
60 -- empty :: Parser a -- neutrales Element, ein Parser der immer fehlschlägt
61 empty = Parser $ \s -> []
62
63 -- <|> :: Parser a -> Parser a -> Parser a -- verknüpft zwei Parser zu einem Parser, welcher beides alternativ parsen kann
64 (Parser p1) <|> (Parser p2) = Parser pbranches
65 where
66 pbranches s
67 | null r1 = r2
68 | null r2 = r1
69 | otherwise = r1 ++ r2
70 where
71 r1 = p1 s
72 r2 = p2 s
73
74-- Basic Parsers
75satisfy :: (Char -> Bool) -> Parser Char -- parse a desired character
76satisfy p = Parser check
77 where
78 check (c:s) | p c = [(c,s)] -- successful
79 check _ = [ ] -- no parse
80
81char :: Char -> Parser Char -- parse a certain character
82char c = satisfy (c ==)
83
84space :: Parser Char -- exactly one space character
85space = satisfy isSpace
86
87alpha :: Parser Char -- any alpha chars (no numbers or special symbols)
88alpha = satisfy isAlpha
89
90upper :: Parser Char
91upper = satisfy isUpper
92
93lower :: Parser Char
94lower = satisfy isLower
95
96digit :: Parser Int
97digit = n2n <$> satisfy isDigit
98 where
99 n2n '0' = 0
100 n2n '1' = 1
101 n2n '2' = 2
102 n2n '3' = 3
103 n2n '4' = 4
104 n2n '5' = 5
105 n2n '6' = 6
106 n2n '7' = 7
107 n2n '8' = 8
108 n2n '9' = 9
109
110-- Zusammengesetze Parser
111string :: Parser String -- acccepts any string
112string = some (satisfy $ (\_ -> True))
113
114keyword :: String -> Parser String -- accepts only a certain string
115keyword = traverse char
116
117name :: Parser String -- akzeptiert alle Strings aus Buchstaben
118name = some $ satisfy isAlpha
119
120name1 :: Parser String -- akzeptiert alle Strings aus Buchstaben mit großen Anfangsbuchstaben
121name1 = (:) <$> (satisfy isUpper) <*> (many $ satisfy isAlpha)
122
123skipSpaces :: Parser () -- zero or more spaces skipped
124skipSpaces = (\_ -> ()) <$> many space
125
126skipSpaces1 :: Parser () -- one or more spaces skipped
127skipSpaces1 = (\_ -> ()) <$> some space
128
129natural :: Parser Int -- parse natural number
130natural = accum <$> some digit
131 where
132 accum = foldl (\a n -> n + a*10) 0
133
134ptwo :: Parser a -> Parser b -> Parser (a,b) -- parse 2-tupel
135ptwo p1 p2 = (,) <$> p1 <*> p2
136
137pPair :: Parser a -> Parser b -> Parser (a,b) -- parse (,)-encased pair
138pPair p1 p2 = (,) <$> (char '(' *> p1 <* char ',') <*> p2 <* char ')'
139
140
141{- instance Functor ((,) a) is defined in `GHC.Base'
142mapSnd :: (b -> c) -> (a,b) -> (a,c)
143mapSnd f (x,y) = (x,(f y))
144-}
145
146
147-- Beispiele:
148--
149-- > parse upper "A"
150-- Just 'A'
151--
152-- > parse upper "AB"
153-- Nothing
154--
155-- > runParser upper "AB"
156-- [('A',"B")]
157--
158-- > runParser natural "12a"
159-- [(12,"a"),(1,"2a")]
160--
161-- > runParser (ptwo natural string) "12a"
162-- [((12,"a"),""),((1,"2a"),""),((1,"2"),"a")]
163
164
165
166-- AUFGABE 6-4
167--
168-- Die geforderten Lösungen sind alles Einzeiler,
169-- welche im wesentlichen <$> und <*> einsetzen.
170-- Als Muster sollten Sie sich die Funktionen ptwo, name1 und später evtl. pPair anschauen!
171--
172-- a)
173-- Schreiben Sie einen Parser für den Typ Person:
174data Person = Person String deriving (Eq, Show)
175
176-- Namen dürfen nur aus Buchstaben bestehen und müssen mit Großbuchstaben beginnen.
177--
178-- Hinweis: schauen Sie sich die Funktionen name und name1 an.
179-- Diese können Sie nicht nur verwenden, sondern dienen auch als Beispiel.
180--
181-- Zusatz: Ihr Parser verlangt zuerst das Schlüsselwort "Person" vor dem eigentlichen Namen
182-- Schlagen Sie dazu die Funktion *> im Modul Control.Applicative nach!
183
184-- Beispiele:
185-- > parse pPerson "Fred"
186-- Just (Person "Fred")
187--
188-- > runParser pPerson "Fred"
189-- [(Person "Fred",""),(Person "Fre","d"),(Person "Fr","ed"),(Person "F","red")]
190--
191-- > parse pPerson2 "Person Fred"
192-- Just (Person "Fred")
193--
194-- > parse pPerson2 "Fred"
195-- Nothing
196
197pPerson1 :: Parser Person
198pPerson1 = Person <$> name1
199
200pPerson2 :: Parser Person
201pPerson2 = keyword "Person" *> skipSpaces *> pPerson1
202
203
204-- b) Parsen Sie einen Student mit Matrikelnummer:
205data Student = Student String Int deriving (Eq, Show)
206
207-- Zusatz: Ihr Parser verlangt zuerst das Schlüsselwort "Student" vor dem eigentlichen Namen
208-- und erlaubt (oder fordert) Leerzeichen zwischen Student, Namen und Nummer!
209-- skipSpaces und skipSpaces1 helfen hier weiter!
210
211pStudent1 :: Parser Student
212pStudent1 = Student <$> name1 <* skipSpaces <*> natural
213
214pStudent2 :: Parser Student
215pStudent2 = keyword "Student" *> skipSpaces *> pStudent1
216
217-- Beispiele:
218-- > parse pStudent1 "Fred0123"
219-- Just (Student "Fred012" 3)
220--
221-- > parse pStudent2 "Student Fred 0123"
222-- Just (Student "Fred" 123)
223--
224-- > parse pStudent2 "StudentFred0123"
225-- Nothing
226
227
228-- c) Parsen Sie einen (Hochschul-)Lehrer:
229data Lehrer = Prof String | Dozent Titel String deriving (Eq, Show)
230data Titel = Dr | Herr deriving (Eq, Show)
231-- Verwenden Sie dazu die Funktion <|>, welche Sie ebenfalls in Modul Control.Applicative nachschlagen können!
232-- Es ist dazu hilfreich, mehrere einzelne Funktionen zu schreiben,
233-- wie hier im Gerüst vorgegeben. (Das ist aber kein Zwang!)
234
235prof :: Parser Lehrer
236prof = Prof <$ keyword "Prof" <* skipSpaces <*> name1
237
238dozent :: Parser Lehrer
239dozent = Dozent <$> titel <* skipSpaces <*> name1
240
241titel :: Parser Titel
242titel = (Dr <$ keyword "Dr") <|> (Herr <$ keyword "Herr")
243
244lehrer :: Parser Lehrer
245lehrer = prof <|> dozent
246
247-- Beispiele:
248--
249-- > parse lehrer "Prof Martin"
250-- Just (Prof "Martin")
251--
252-- > parse lehrer "Dr Jost"
253-- Just (Dozent Dr "Jost")
254--
255-- > parse prof "Dr Jost"
256-- Nothing