Merge branch 'master' of github.com:FFPiHaskell/Vorlesung2016
This commit is contained in:
commit
6b48de8bec
BIN
Folien/vorlesung4.pdf
Normal file
BIN
Folien/vorlesung4.pdf
Normal file
Binary file not shown.
@ -1,90 +1,116 @@
|
|||||||
# Übungsblatt 1
|
-- Übungsblatt 1
|
||||||
|
-- =============
|
||||||
|
--
|
||||||
|
-- Typtheorie
|
||||||
|
-- ----------
|
||||||
|
--
|
||||||
|
-- Schreiben Sie alle **möglichen** Implementationen der folgenden
|
||||||
|
-- Funktionen. Wozu könnte `fun2` nützlich sein?
|
||||||
|
|
||||||
## Typtheorie
|
|
||||||
|
|
||||||
Schreiben Sie alle **möglichen** Implementationen der folgenden Funktionen. Wozu könnte `fun2` nützlich sein?
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
fun1 :: a -> a
|
fun1 :: a -> a
|
||||||
fun1 = _fun1
|
fun1 a = a
|
||||||
|
|
||||||
|
-- id
|
||||||
|
|
||||||
fun2 :: a -> b -> a
|
fun2 :: a -> b -> a
|
||||||
fun2 = _fun2
|
fun2 a _ = a
|
||||||
|
|
||||||
fun3 :: (Eq a) => a -> a -> Bool
|
fun3 :: (Eq a) => a -> a -> Bool
|
||||||
fun3 = _fun3
|
fun3 _ _ = True
|
||||||
```
|
fun3 _ _ = False
|
||||||
|
fun3 = (==)
|
||||||
|
fun3 = (/=)
|
||||||
|
|
||||||
Wir haben in der Vorlesung parametrisierte Typen kennengelernt. Der simpelste hiervon ist `Identity`, der nur einen anderen Typen einpackt.
|
-- Wir haben in der Vorlesung parametrisierte Typen kennengelernt. Der
|
||||||
|
-- simpelste hiervon ist `Identity`, der nur einen anderen Typen einpackt.
|
||||||
|
|
||||||
```haskell
|
|
||||||
data Identity a = Identity a
|
data Identity a = Identity a
|
||||||
```
|
|
||||||
|
|
||||||
Diese Definition stellt uns automatisch den Konstruktor `Identity :: a -> Identity a` zur Verfügung, der ein `a` einpackt. Schreiben Sie die Funktion
|
-- Diese Definition stellt uns automatisch den Konstruktor
|
||||||
|
-- `Identity :: a -> Identity a` zur Verfügung, der ein `a` einpackt.
|
||||||
|
-- Schreiben Sie die Funktion
|
||||||
|
|
||||||
```haskell
|
|
||||||
unIdentity :: Identity a -> a
|
unIdentity :: Identity a -> a
|
||||||
unIdentity = _unIdentity
|
unIdentity (Identity a) = a
|
||||||
```
|
|
||||||
|
|
||||||
welche diesen Vorgang wieder rückgängig macht.
|
-- welche diesen Vorgang wieder rückgängig macht.
|
||||||
|
--
|
||||||
|
-- Angenommen, Sie hätten nun ein Wert vom Typen `Identity a` und eine
|
||||||
|
-- Funktion mit dem Typen `a -> b`. Wie wenden Sie diese auf das `a`
|
||||||
|
-- "innerhalb" des `Identity` an um ein `Identity b` herzustellen?
|
||||||
|
-- Schreiben Sie also eine Funktion
|
||||||
|
|
||||||
Angenommen, Sie hätten nun ein Wert vom Typen `Identity a` und eine Funktion mit dem Typen `a -> b`. Wie wenden Sie diese auf das `a` "innerhalb" des `Identity` an um ein `Identity b` herzustellen? Schreiben Sie also eine Funktion
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
mapIdentity :: (a -> b) -> Identity a -> Identity b
|
mapIdentity :: (a -> b) -> Identity a -> Identity b
|
||||||
mapIdentity = _mapIdentity
|
mapIdentity f a = Identity . f . unIdentity
|
||||||
```
|
|
||||||
|
|
||||||
**Hinweis:** Es gibt *zwei* prinzipielle Vorgehen dieses zu implementieren. Kommen Sie auf beide?
|
--mapIdentity f (Identity a) = Identity (f a)
|
||||||
|
|
||||||
|
-- **Hinweis:** Es gibt *zwei* prinzipielle Vorgehen dieses zu
|
||||||
|
-- implementieren. Kommen Sie auf beide?
|
||||||
|
--
|
||||||
|
-- Funktionen sind auch nur Typen
|
||||||
|
-- ------------------------------
|
||||||
|
--
|
||||||
|
-- Datentypen können auch Funktionen enthalten. Sehen Sie sich einmal den
|
||||||
|
-- Datentypen
|
||||||
|
|
||||||
## Funktionen sind auch nur Typen
|
|
||||||
|
|
||||||
Datentypen können auch Funktionen enthalten. Sehen Sie sich einmal den Datentypen
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
data Pred a = Pred (a -> Bool)
|
data Pred a = Pred (a -> Bool)
|
||||||
```
|
|
||||||
|
|
||||||
an. Hier wird ein Prädikat definiert, welches (gegeben einen Datentyp `a`) eine Funktion gespeichert hat, die `a` in einen `Bool` umwandeln kann (etwa um irgendwas zu filtern/selektieren/löschen/..., wenn man dies an eine weitere Funktion übergibt).
|
-- an. Hier wird ein Prädikat definiert, welches (gegeben einen Datentyp
|
||||||
|
-- `a`) eine Funktion gespeichert hat, die `a` in einen `Bool` umwandeln
|
||||||
|
-- kann (etwa um irgendwas zu filtern/selektieren/löschen/..., wenn man
|
||||||
|
-- dies an eine weitere Funktion übergibt).
|
||||||
|
--
|
||||||
|
-- Auch hier können Sie eine Funktion schreiben, die das `Pred a` wieder
|
||||||
|
-- "auspackt". Definieren Sie
|
||||||
|
|
||||||
Auch hier können Sie eine Funktion schreiben, die das `Pred a` wieder "auspackt". Definieren Sie
|
unPred :: Pred a -> a -> Bool
|
||||||
|
unPred (Pred a) = a
|
||||||
|
|
||||||
```haskell
|
-- Da Haskell-Funktionen aber "gecurried" sind (mehr dazu in der
|
||||||
unPred :: Pred a -> (a -> Bool)
|
-- Vorlesung), können Sie die Klammern hinten in der Signatur auch
|
||||||
unPred = _unPred
|
-- weglassen und erhalten `unPred :: Pred a -> a -> Bool`, was man zugleich
|
||||||
```
|
-- als "wende `Pred a` an, wenn du ein `a` bekommst" lesen kann. In der Tat
|
||||||
|
-- sind beide Funktionen identisch (wieso?).
|
||||||
|
--
|
||||||
|
-- Bonus
|
||||||
|
--
|
||||||
|
-- Was für eine Funktion bräuchten Sie um ein `Pred a` in ein `Pred b`
|
||||||
|
-- umzuwandeln? Können Sie diese implementieren?
|
||||||
|
|
||||||
Da Haskell-Funktionen aber "gecurried" sind (mehr dazu in der Vorlesung), können Sie die Klammern hinten in der Signatur auch weglassen und erhalten `unPred :: Pred a -> a -> Bool`, was man zugleich als "wende `Pred a` an, wenn du ein `a` bekommst" lesen kann.
|
|
||||||
In der Tat sind beide Funktionen identisch (wieso?).
|
|
||||||
|
|
||||||
### Bonus
|
|
||||||
|
|
||||||
Was für eine Funktion bräuchten Sie um ein `Pred a` in ein `Pred b` umzuwandeln? Können Sie diese implementieren?
|
|
||||||
|
|
||||||
```haskell
|
|
||||||
mapPred :: _fun -> Pred a -> Pred b
|
mapPred :: _fun -> Pred a -> Pred b
|
||||||
mapPred = _mapPred
|
mapPred f (Pred a) = _mapPred
|
||||||
```
|
|
||||||
|
|
||||||
## Neue Typen erfinden
|
-- Neue Typen erfinden
|
||||||
|
-- -------------------
|
||||||
|
--
|
||||||
|
-- In Haskell ist ein zentraler Vorgehenspunkt das Definieren und Verwenden
|
||||||
|
-- von eigenen Datentypen. Zur Erinnerung; es gibt zwei Möglichkeiten, die
|
||||||
|
-- man miteinander kombinieren kann: `data Prod a b c = Prod a b c`
|
||||||
|
-- (Produkttyp) benötigt sowohl `a`, `b` als auch `c` um einen Wert zu
|
||||||
|
-- erzeugen, `data Sum a b = Sum1 a | Sum2 b` (Summentyp) braucht entweder
|
||||||
|
-- ein `a` um durch den Konstruktor `Sum1` ein `Sum a b` zu erzeugen oder
|
||||||
|
-- ein `b` um durch den Konstruktor `Sum2` ein `Sum a b` zu erzeugen.
|
||||||
|
--
|
||||||
|
-- Definieren Sie einen Datentypen `Vielleicht a`, der zwei Konstruktoren
|
||||||
|
-- besitzt: Einen Konstruktor, mit dem durch ein `a` ein `Vielleicht a`
|
||||||
|
-- konstruiert wird und ein zweiter Konstruktor, der keinen Wert nimmt,
|
||||||
|
-- sondern die "Abwesenheit eines `a`" symbolisieren soll.
|
||||||
|
|
||||||
In Haskell ist ein zentraler Vorgehenspunkt das Definieren und Verwenden von eigenen Datentypen. Zur Erinnerung; es gibt zwei Möglichkeiten, die man miteinander kombinieren kann: `data Prod a b c = Prod a b c` (Produkttyp) benötigt sowohl `a`, `b` als auch `c` um einen Wert zu erzeugen, `data Sum a b = Sum1 a | Sum2 b` (Summentyp) braucht entweder ein `a` um durch den Konstruktor `Sum1` ein `Sum a b` zu erzeugen oder ein `b` um durch den Konstruktor `Sum2` ein `Sum a b` zu erzeugen.
|
data Vielleicht a = Exercise
|
||||||
|
|
||||||
Definieren Sie einen Datentypen `Vielleicht a`, der zwei Konstruktoren besitzt: Einen Konstruktor, mit dem durch ein `a` ein `Vielleicht a` konstruiert wird und ein zweiter Konstruktor, der keinen Wert nimmt, sondern die "Abwesenheit eines `a`" symbolisieren soll.
|
-- Können Sie hier eine Funktion schreiben, die das `a` extrahiert? Wenn
|
||||||
|
-- ja, implementieren Sie diese; wenn nein, geben Sie eine kurze
|
||||||
|
-- Begründung.
|
||||||
|
--
|
||||||
|
-- Wie würden Sie mittels einer Funktion `a -> b` ein `Vielleicht a` in ein
|
||||||
|
-- `Vielleicht b` wandeln? Implementieren Sie
|
||||||
|
|
||||||
Können Sie hier eine Funktion schreiben, die das `a` extrahiert? Wenn ja, implementieren Sie diese; wenn nein, geben Sie eine kurze Begründung.
|
|
||||||
|
|
||||||
Wie würden Sie mittels einer Funktion `a -> b` ein `Vielleicht a` in ein `Vielleicht b` wandeln? Implementieren Sie
|
|
||||||
```haskell
|
|
||||||
mapVielleicht :: (a -> b) -> Vielleicht a -> Vielleicht b
|
mapVielleicht :: (a -> b) -> Vielleicht a -> Vielleicht b
|
||||||
mapVielleicht = _mapVielleicht
|
mapVielleicht = _mapVielleicht
|
||||||
```
|
|
||||||
|
|
||||||
### Bonus
|
|
||||||
|
|
||||||
Man kann Typen natürlich auch Schachteln. Worin liegt eigentlich der Unterschied zwischen einem `Pred (Vielleicht a)` und einem `Vielleicht (Pred a)`? Oder sind diese identisch?
|
|
||||||
|
|
||||||
|
|
||||||
|
-- Bonus
|
||||||
|
--
|
||||||
|
-- Man kann Typen natürlich auch Schachteln. Worin liegt eigentlich der
|
||||||
|
-- Unterschied zwischen einem `Pred (Vielleicht a)` und einem
|
||||||
|
-- `Vielleicht (Pred a)`? Oder sind diese identisch?
|
||||||
|
128
Übungen/Blatt1.solution.hs
Normal file
128
Übungen/Blatt1.solution.hs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
-- Übungsblatt 1
|
||||||
|
-- =============
|
||||||
|
--
|
||||||
|
-- Typtheorie
|
||||||
|
-- ----------
|
||||||
|
--
|
||||||
|
-- Schreiben Sie alle **möglichen** Implementationen der folgenden
|
||||||
|
-- Funktionen. Wozu könnte `fun2` nützlich sein?
|
||||||
|
|
||||||
|
fun1 :: a -> a
|
||||||
|
fun1 a = a
|
||||||
|
|
||||||
|
-- id
|
||||||
|
|
||||||
|
fun2 :: a -> b -> a
|
||||||
|
fun2 a _ = a
|
||||||
|
|
||||||
|
fun3 :: (Eq a) => a -> a -> Bool
|
||||||
|
fun3 _ _ = True
|
||||||
|
--fun3 _ _ = False
|
||||||
|
--fun3 = (==)
|
||||||
|
--fun3 = (/=)
|
||||||
|
|
||||||
|
-- Wir haben in der Vorlesung parametrisierte Typen kennengelernt. Der
|
||||||
|
-- simpelste hiervon ist `Identity`, der nur einen anderen Typen einpackt.
|
||||||
|
|
||||||
|
data Identity a = Identity a
|
||||||
|
|
||||||
|
-- Diese Definition stellt uns automatisch den Konstruktor
|
||||||
|
-- `Identity :: a -> Identity a` zur Verfügung, der ein `a` einpackt.
|
||||||
|
-- Schreiben Sie die Funktion
|
||||||
|
|
||||||
|
unIdentity :: Identity a -> a
|
||||||
|
unIdentity (Identity a) = a
|
||||||
|
|
||||||
|
-- welche diesen Vorgang wieder rückgängig macht.
|
||||||
|
--
|
||||||
|
-- Angenommen, Sie hätten nun ein Wert vom Typen `Identity a` und eine
|
||||||
|
-- Funktion mit dem Typen `a -> b`. Wie wenden Sie diese auf das `a`
|
||||||
|
-- "innerhalb" des `Identity` an um ein `Identity b` herzustellen?
|
||||||
|
-- Schreiben Sie also eine Funktion
|
||||||
|
|
||||||
|
mapIdentity :: (a -> b) -> Identity a -> Identity b
|
||||||
|
mapIdentity f = Identity . f . unIdentity
|
||||||
|
|
||||||
|
--mapIdentity f (Identity a) = Identity (f a)
|
||||||
|
|
||||||
|
-- **Hinweis:** Es gibt *zwei* prinzipielle Vorgehen dieses zu
|
||||||
|
-- implementieren. Kommen Sie auf beide?
|
||||||
|
--
|
||||||
|
-- Funktionen sind auch nur Typen
|
||||||
|
-- ------------------------------
|
||||||
|
--
|
||||||
|
-- Datentypen können auch Funktionen enthalten. Sehen Sie sich einmal den
|
||||||
|
-- Datentypen
|
||||||
|
|
||||||
|
data Pred a = Pred (a -> Bool)
|
||||||
|
|
||||||
|
-- an. Hier wird ein Prädikat definiert, welches (gegeben einen Datentyp
|
||||||
|
-- `a`) eine Funktion gespeichert hat, die `a` in einen `Bool` umwandeln
|
||||||
|
-- kann (etwa um irgendwas zu filtern/selektieren/löschen/..., wenn man
|
||||||
|
-- dies an eine weitere Funktion übergibt).
|
||||||
|
--
|
||||||
|
-- Auch hier können Sie eine Funktion schreiben, die das `Pred a` wieder
|
||||||
|
-- "auspackt". Definieren Sie
|
||||||
|
|
||||||
|
unPred :: Pred a -> a -> Bool
|
||||||
|
unPred (Pred a) = a
|
||||||
|
|
||||||
|
-- Da Haskell-Funktionen aber "gecurried" sind (mehr dazu in der
|
||||||
|
-- Vorlesung), können Sie die Klammern hinten in der Signatur auch
|
||||||
|
-- weglassen und erhalten `unPred :: Pred a -> a -> Bool`, was man zugleich
|
||||||
|
-- als "wende `Pred a` an, wenn du ein `a` bekommst" lesen kann. In der Tat
|
||||||
|
-- sind beide Funktionen identisch (wieso?).
|
||||||
|
--
|
||||||
|
-- Bonus
|
||||||
|
--
|
||||||
|
-- Was für eine Funktion bräuchten Sie um ein `Pred a` in ein `Pred b`
|
||||||
|
-- umzuwandeln? Können Sie diese implementieren?
|
||||||
|
|
||||||
|
mapPred :: (b -> a) -> Pred a -> Pred b
|
||||||
|
mapPred f (Pred a) = Pred (a . f)
|
||||||
|
|
||||||
|
-- Neue Typen erfinden
|
||||||
|
-- -------------------
|
||||||
|
--
|
||||||
|
-- In Haskell ist ein zentraler Vorgehenspunkt das Definieren und Verwenden
|
||||||
|
-- von eigenen Datentypen. Zur Erinnerung; es gibt zwei Möglichkeiten, die
|
||||||
|
-- man miteinander kombinieren kann: `data Prod a b c = Prod a b c`
|
||||||
|
-- (Produkttyp) benötigt sowohl `a`, `b` als auch `c` um einen Wert zu
|
||||||
|
-- erzeugen, `data Sum a b = Sum1 a | Sum2 b` (Summentyp) braucht entweder
|
||||||
|
-- ein `a` um durch den Konstruktor `Sum1` ein `Sum a b` zu erzeugen oder
|
||||||
|
-- ein `b` um durch den Konstruktor `Sum2` ein `Sum a b` zu erzeugen.
|
||||||
|
--
|
||||||
|
-- Definieren Sie einen Datentypen `Vielleicht a`, der zwei Konstruktoren
|
||||||
|
-- besitzt: Einen Konstruktor, mit dem durch ein `a` ein `Vielleicht a`
|
||||||
|
-- konstruiert wird und ein zweiter Konstruktor, der keinen Wert nimmt,
|
||||||
|
-- sondern die "Abwesenheit eines `a`" symbolisieren soll.
|
||||||
|
|
||||||
|
data Vielleicht a = Etwas a
|
||||||
|
| Nichts
|
||||||
|
|
||||||
|
-- Können Sie hier eine Funktion schreiben, die das `a` extrahiert? Wenn
|
||||||
|
-- ja, implementieren Sie diese; wenn nein, geben Sie eine kurze
|
||||||
|
-- Begründung.
|
||||||
|
--
|
||||||
|
-- Wie würden Sie mittels einer Funktion `a -> b` ein `Vielleicht a` in ein
|
||||||
|
-- `Vielleicht b` wandeln? Implementieren Sie
|
||||||
|
|
||||||
|
mapVielleicht :: (a -> b) -> Vielleicht a -> Vielleicht b
|
||||||
|
mapVielleicht f (Etwas a) = Etwas (f a)
|
||||||
|
mapVielleicht f Nichts = Nichts
|
||||||
|
|
||||||
|
-- Bonus
|
||||||
|
--
|
||||||
|
-- Man kann Typen natürlich auch Schachteln. Worin liegt eigentlich der
|
||||||
|
-- Unterschied zwischen einem `Pred (Vielleicht a)` und einem
|
||||||
|
-- `Vielleicht (Pred a)`? Oder sind diese identisch?
|
||||||
|
|
||||||
|
fun4 :: Pred (Vielleicht a) -> x
|
||||||
|
fun4 (Pred a) = undefined
|
||||||
|
|
||||||
|
fun5 :: Vielleicht (Pred a) -> x
|
||||||
|
fun5 (Etwas (Pred a)) = undefined
|
||||||
|
fun5 Nichts = undefined
|
||||||
|
|
||||||
|
|
||||||
|
main = putStrLn "compiles"
|
125
Übungen/Blatt2.solution.hs
Normal file
125
Übungen/Blatt2.solution.hs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
-- # Übungsblatt 2
|
||||||
|
--
|
||||||
|
-- ## Throat-Clearing
|
||||||
|
--
|
||||||
|
-- a.k.a. Imports, damit der Code funktioniert.
|
||||||
|
|
||||||
|
import Control.Monad
|
||||||
|
import Data.Functor
|
||||||
|
import Data.Monoid
|
||||||
|
|
||||||
|
-- ## Functor
|
||||||
|
--
|
||||||
|
-- Sie haben in der Vorlesung die Typklasse `Functor` kennengelernt. Zur Erinnerung:
|
||||||
|
--
|
||||||
|
-- class Functor f where
|
||||||
|
-- fmap :: (a -> b) -> f a -> f b
|
||||||
|
--
|
||||||
|
-- Nehmen sie an, sie hätten folgende Datentypen gegeben, für die alle eine `Functor`-Instanz existiert und eindeutig ist:
|
||||||
|
|
||||||
|
data Identity a = Identity { unIdentity :: a }
|
||||||
|
|
||||||
|
instance Functor Identity where
|
||||||
|
fmap f (Identity a) = Identity (f a)
|
||||||
|
|
||||||
|
data Vielleicht a = Etwas a
|
||||||
|
| Nichts
|
||||||
|
|
||||||
|
instance Functor Vielleicht where
|
||||||
|
fmap f (Etwas a) = Etwas (f a)
|
||||||
|
fmap f Nichts = Nichts
|
||||||
|
|
||||||
|
data EntwederOder b a = Entweder a
|
||||||
|
| Oder b
|
||||||
|
|
||||||
|
instance Functor (EntwederOder c) where
|
||||||
|
fmap f (Entweder a) = Entweder (f a)
|
||||||
|
fmap _ (Oder b) = Oder b
|
||||||
|
|
||||||
|
data GameVector b a = V3 a a a
|
||||||
|
| VStrange [a]
|
||||||
|
| Neighbours [GameVector b a]
|
||||||
|
| EntwederOder b (GameVector b a)
|
||||||
|
|
||||||
|
instance Functor (GameVector c) where
|
||||||
|
fmap f (V3 x y z) = V3 (f x) (f y) (f z)
|
||||||
|
fmap f (VStrange l) = VStrange (f <$> l)
|
||||||
|
fmap f (Neighbours l) = Neighbours (fmap f <$> l)
|
||||||
|
fmap f (EntwederOder b v) = EntwederOder b (f <$> v)
|
||||||
|
|
||||||
|
-- Schreiben sie hierzu die jeweiligen `Functor`-Instanzen.
|
||||||
|
--
|
||||||
|
-- ## Besser und allgemeiner
|
||||||
|
--
|
||||||
|
-- Vereinfachen und verallgemeinern sie folgenden Ausdrücke so weit wie möglich und geben die sie dadurch entstehenden Typsignaturen an.
|
||||||
|
-- Bedenken sie, dass wenn sie auf eine Typklasse abstrahieren, sie die gesamten Gesetze der Typklasse benutzen können.
|
||||||
|
--
|
||||||
|
-- Kann die Funktion nachher mehr als vorher?
|
||||||
|
--
|
||||||
|
-- *Bonus*: Hat sich an der Laufzeit etwas verändert?
|
||||||
|
|
||||||
|
mystery1 :: [[a]] -> [[a]]
|
||||||
|
mystery1 = map (++[])
|
||||||
|
|
||||||
|
-- List is Functor => fmap instead of map
|
||||||
|
mystery1' :: Functor f => f [a] -> f [a]
|
||||||
|
mystery1' = fmap (++[])
|
||||||
|
|
||||||
|
-- List is a Monoid => ++ == <> && [] == mempty
|
||||||
|
mystery1'' :: (Functor f, Monoid m) => f m -> f m
|
||||||
|
mystery1'' = fmap (<> mempty)
|
||||||
|
|
||||||
|
-- Monoid-Law: (<> mempty) == id
|
||||||
|
mystery1''' :: Functor f => f a -> f a
|
||||||
|
mystery1''' = fmap id
|
||||||
|
|
||||||
|
-- Functor-Law: fmap id == id
|
||||||
|
mystery1'''' :: a -> a
|
||||||
|
mystery1'''' = id
|
||||||
|
|
||||||
|
mystery2 :: (Eq a) => a -> a -> a -> Bool
|
||||||
|
mystery2 x y z
|
||||||
|
| x == y || y == z = True
|
||||||
|
| otherwise = False
|
||||||
|
|
||||||
|
mystery3 :: (MonadPlus f, Eq a) => (a -> a) -> a -> f a -> f a
|
||||||
|
mystery3 f a l = mfilter (==a) (f <$> l)
|
||||||
|
|
||||||
|
mystery3' :: Eq a => (a -> a) -> a -> [a] -> [a]
|
||||||
|
mystery3' f a l = filter (==a) (f <$> l)
|
||||||
|
-- post a l'
|
||||||
|
-- where
|
||||||
|
-- l' = map f l
|
||||||
|
-- post a (x:xs)
|
||||||
|
-- | a == x = x : post a xs
|
||||||
|
-- | otherwise = post a xs
|
||||||
|
-- post _ [] = []
|
||||||
|
|
||||||
|
mystery4 :: (Int -> Bool)
|
||||||
|
-> Vielleicht (EntwederOder String Int)
|
||||||
|
-> Vielleicht (EntwederOder String Bool)
|
||||||
|
mystery4 f (Etwas (Entweder a)) = Etwas . Entweder . f $ a
|
||||||
|
mystery4 _ (Etwas (Oder b)) = Etwas (Oder b)
|
||||||
|
mystery4 _ Nichts = Nichts
|
||||||
|
|
||||||
|
mystery4'' :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
|
||||||
|
mystery4'' f ve = fmap (fmap f) ve
|
||||||
|
|
||||||
|
mystery4' :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
|
||||||
|
mystery4' = fmap . fmap
|
||||||
|
|
||||||
|
-- ## Bonus
|
||||||
|
--
|
||||||
|
-- Es gibt von dem bekannten Spiel 2048 eine Haskell-Implementation für die Kommandozeile in unter 100 Zeilen. Diese ist zu finde unter
|
||||||
|
-- https://github.com/gregorulm/h2048/blob/master/h2048.hs
|
||||||
|
--
|
||||||
|
-- Sie können diesen Code mit `GHC` kompilieren oder im `ghci` ausführen (`main` ist die Start-Funktion).
|
||||||
|
--
|
||||||
|
-- Was für Prinzipielle Vorgehenspunkte können sie erkennen?
|
||||||
|
-- Eine kleine Erklärung gibt es im Blog der Erstellers: http://gregorulm.com/2048-in-90-lines-haskell/
|
||||||
|
--
|
||||||
|
-- Keine Angst, sie müssen dies noch nicht verstehen, aber es soll verdeutlichen, wie viel man mit extrem wenig erreichen kann. Viele der Abgabeprojekte werden in dieser Größenordnung liegen (aber meist noch so etwas wie ein GUI o.ä. benötigen). Versuchen sie einfach den Code kaputtzuspielen (z.b. Tasten ändern, Siegbedingung ändern, Cheats einbauen, ...).
|
||||||
|
--
|
||||||
|
-- Viel Spass beim Spielen! :)
|
||||||
|
|
||||||
|
main = putStrLn "compiles"
|
113
Übungen/Blatt3.hs
Normal file
113
Übungen/Blatt3.hs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
-- Übungsblatt 3
|
||||||
|
-- =============
|
||||||
|
--
|
||||||
|
-- Throat-Clearing
|
||||||
|
-- ---------------
|
||||||
|
--
|
||||||
|
-- a.k.a. Imports, damit der Code funktioniert.
|
||||||
|
|
||||||
|
module MonadExercise where
|
||||||
|
import Control.Applicative
|
||||||
|
import Control.Monad
|
||||||
|
import Data.Monoid
|
||||||
|
|
||||||
|
-- Vorwort
|
||||||
|
-- -------
|
||||||
|
--
|
||||||
|
-- Die Typklassen, die auf diesem Zettel implementiert werden sollen sind
|
||||||
|
-- teilweise nicht eindeutig. Ein gutes *Indiz* für eine falsche
|
||||||
|
-- implementation kann sein, dass Informationen "weggeschmissen" werden -
|
||||||
|
-- allerdings muss man bei anderen Implementationen genau dies machen.
|
||||||
|
--
|
||||||
|
-- Applicative
|
||||||
|
-- -----------
|
||||||
|
--
|
||||||
|
-- Nachdem wir uns letzte Woche ausführlich mit der Typklasse `Functor`
|
||||||
|
-- beschäftigt haben, bauen wir nun darauf auf und definieren die
|
||||||
|
-- Applicative-Instanz. Zur Erinnerung:
|
||||||
|
--
|
||||||
|
-- class Functor f => Applicative f where
|
||||||
|
-- pure :: a -> f a
|
||||||
|
-- <*> :: f (a -> b) -> f a -> f b
|
||||||
|
--
|
||||||
|
-- Nehmen sie an, sie hätten folgende Datentypen mit ihren
|
||||||
|
-- `Functor`-Instanzen gegeben. Schreiben sie jeweils die
|
||||||
|
-- Applicative-Instanz:
|
||||||
|
|
||||||
|
data Identity a = Identity { unIdentity :: a }
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Functor Identity where
|
||||||
|
fmap f (Identity a) = Identity (f a)
|
||||||
|
|
||||||
|
data Vielleicht a = Etwas a
|
||||||
|
| Nichts
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Functor Vielleicht where
|
||||||
|
fmap f (Etwas a) = Etwas (f a)
|
||||||
|
fmap _ Nichts = Nichts
|
||||||
|
|
||||||
|
data EntwederOder b a = Entweder a
|
||||||
|
| Oder b
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Functor (EntwederOder b) where
|
||||||
|
fmap f (Entweder a) = Entweder (f a)
|
||||||
|
fmap _ (Oder b) = Oder b
|
||||||
|
|
||||||
|
data List a = Cons a (List a)
|
||||||
|
| Nil
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Functor List where
|
||||||
|
fmap f (Cons a r) = Cons (f a) (fmap f r)
|
||||||
|
fmap _ Nil = Nil
|
||||||
|
|
||||||
|
instance Monoid (List a) where
|
||||||
|
mempty = Nil
|
||||||
|
mappend Nil bs = bs
|
||||||
|
mappend (Cons a as) bs = Cons a (mappend as bs)
|
||||||
|
|
||||||
|
data V3 a = V3 a a a
|
||||||
|
|
||||||
|
instance Functor V3 where
|
||||||
|
fmap f (V3 x y z) = V3 (f x) (f y) (f z)
|
||||||
|
|
||||||
|
-- Monad
|
||||||
|
-- -----
|
||||||
|
--
|
||||||
|
-- Zu welchen der oben aufgeführten Typen gibt es eine Monaden-Instanz? Wie
|
||||||
|
-- sieht diese aus? Schreiben sie diese (falls möglich).
|
||||||
|
--
|
||||||
|
-- Bonus
|
||||||
|
-- -----
|
||||||
|
|
||||||
|
data Account = Account
|
||||||
|
data Inbox = Inbox
|
||||||
|
data Mail = Mail
|
||||||
|
|
||||||
|
-- Seien folgende Funktionen gegeben:
|
||||||
|
|
||||||
|
login :: Maybe Account
|
||||||
|
login = undefined
|
||||||
|
|
||||||
|
getInbox :: Account -> Maybe Inbox
|
||||||
|
getInbox = undefined
|
||||||
|
|
||||||
|
getMails :: Inbox -> [Mail]
|
||||||
|
getMails = undefined
|
||||||
|
|
||||||
|
safeHead :: [a] -> Maybe a
|
||||||
|
safeHead = undefined
|
||||||
|
|
||||||
|
-- Schreiben sie eine Funktion:
|
||||||
|
|
||||||
|
getFirstMail :: Maybe Mail
|
||||||
|
getFirstMail = undefined
|
||||||
|
|
||||||
|
-- welche die oben genannten 4 Funktionen nutzt um die erste Mail aus dem
|
||||||
|
-- gegebenen Account zurückzuliefern, sofern alles erfolgreich war.
|
||||||
|
--
|
||||||
|
-- Können sie beide Varianten (einmal mittels `do`-notation und einmal mit
|
||||||
|
-- `>>=`) schreiben?
|
113
Übungen/Blatt3.lhs
Normal file
113
Übungen/Blatt3.lhs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
Übungsblatt 3
|
||||||
|
=============
|
||||||
|
|
||||||
|
Throat-Clearing
|
||||||
|
---------------
|
||||||
|
|
||||||
|
a.k.a. Imports, damit der Code funktioniert.
|
||||||
|
|
||||||
|
> module MonadExercise where
|
||||||
|
> import Control.Applicative
|
||||||
|
> import Control.Monad
|
||||||
|
> import Data.Monoid
|
||||||
|
|
||||||
|
Vorwort
|
||||||
|
-------
|
||||||
|
|
||||||
|
Die Typklassen, die auf diesem Zettel implementiert werden sollen sind
|
||||||
|
teilweise nicht eindeutig. Ein gutes *Indiz* für eine falsche
|
||||||
|
implementation kann sein, dass Informationen "weggeschmissen" werden -
|
||||||
|
allerdings muss man bei anderen Implementationen genau dies machen.
|
||||||
|
|
||||||
|
Applicative
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Nachdem wir uns letzte Woche ausführlich mit der Typklasse `Functor`
|
||||||
|
beschäftigt haben, bauen wir nun darauf auf und definieren die
|
||||||
|
Applicative-Instanz. Zur Erinnerung:
|
||||||
|
|
||||||
|
class Functor f => Applicative f where
|
||||||
|
pure :: a -> f a
|
||||||
|
<*> :: f (a -> b) -> f a -> f b
|
||||||
|
|
||||||
|
Nehmen sie an, sie hätten folgende Datentypen mit ihren
|
||||||
|
`Functor`-Instanzen gegeben. Schreiben sie jeweils die
|
||||||
|
Applicative-Instanz:
|
||||||
|
|
||||||
|
> data Identity a = Identity { unIdentity :: a }
|
||||||
|
> deriving (Show, Eq)
|
||||||
|
>
|
||||||
|
> instance Functor Identity where
|
||||||
|
> fmap f (Identity a) = Identity (f a)
|
||||||
|
>
|
||||||
|
> data Vielleicht a = Etwas a
|
||||||
|
> | Nichts
|
||||||
|
> deriving (Show, Eq)
|
||||||
|
>
|
||||||
|
> instance Functor Vielleicht where
|
||||||
|
> fmap f (Etwas a) = Etwas (f a)
|
||||||
|
> fmap _ Nichts = Nichts
|
||||||
|
>
|
||||||
|
> data EntwederOder b a = Entweder a
|
||||||
|
> | Oder b
|
||||||
|
> deriving (Show, Eq)
|
||||||
|
>
|
||||||
|
> instance Functor (EntwederOder b) where
|
||||||
|
> fmap f (Entweder a) = Entweder (f a)
|
||||||
|
> fmap _ (Oder b) = Oder b
|
||||||
|
>
|
||||||
|
> data List a = Cons a (List a)
|
||||||
|
> | Nil
|
||||||
|
> deriving (Show, Eq)
|
||||||
|
>
|
||||||
|
> instance Functor List where
|
||||||
|
> fmap f (Cons a r) = Cons (f a) (fmap f r)
|
||||||
|
> fmap _ Nil = Nil
|
||||||
|
>
|
||||||
|
> instance Monoid (List a) where
|
||||||
|
> mempty = Nil
|
||||||
|
> mappend Nil bs = bs
|
||||||
|
> mappend (Cons a as) bs = Cons a (mappend as bs)
|
||||||
|
>
|
||||||
|
> data V3 a = V3 a a a
|
||||||
|
>
|
||||||
|
> instance Functor V3 where
|
||||||
|
> fmap f (V3 x y z) = V3 (f x) (f y) (f z)
|
||||||
|
|
||||||
|
Monad
|
||||||
|
-----
|
||||||
|
|
||||||
|
Zu welchen der oben aufgeführten Typen gibt es eine Monaden-Instanz? Wie
|
||||||
|
sieht diese aus? Schreiben sie diese (falls möglich).
|
||||||
|
|
||||||
|
Bonus
|
||||||
|
-----
|
||||||
|
|
||||||
|
> data Account = Account
|
||||||
|
> data Inbox = Inbox
|
||||||
|
> data Mail = Mail
|
||||||
|
|
||||||
|
Seien folgende Funktionen gegeben:
|
||||||
|
|
||||||
|
> login :: Maybe Account
|
||||||
|
> login = undefined
|
||||||
|
>
|
||||||
|
> getInbox :: Account -> Maybe Inbox
|
||||||
|
> getInbox = undefined
|
||||||
|
>
|
||||||
|
> getMails :: Inbox -> [Mail]
|
||||||
|
> getMails = undefined
|
||||||
|
>
|
||||||
|
> safeHead :: [a] -> Maybe a
|
||||||
|
> safeHead = undefined
|
||||||
|
|
||||||
|
Schreiben sie eine Funktion:
|
||||||
|
|
||||||
|
> getFirstMail :: Maybe Mail
|
||||||
|
> getFirstMail = undefined
|
||||||
|
|
||||||
|
welche die oben genannten 4 Funktionen nutzt um die erste Mail aus dem
|
||||||
|
gegebenen Account zurückzuliefern, sofern alles erfolgreich war.
|
||||||
|
|
||||||
|
Können sie beide Varianten (einmal mittels `do`-notation und einmal mit
|
||||||
|
`>>=`) schreiben?
|
101
Übungen/Blatt3.md
Normal file
101
Übungen/Blatt3.md
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# Übungsblatt 3
|
||||||
|
|
||||||
|
## Throat-Clearing
|
||||||
|
|
||||||
|
a.k.a. Imports, damit der Code funktioniert.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
import Control.Applicative
|
||||||
|
import Control.Monad
|
||||||
|
import Data.Monoid
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vorwort
|
||||||
|
|
||||||
|
Die Typklassen, die auf diesem Zettel implementiert werden sollen sind teilweise nicht eindeutig. Ein gutes *Indiz* für eine falsche implementation kann sein, dass Informationen "weggeschmissen" werden - allerdings muss man bei anderen Implementationen genau dies machen.
|
||||||
|
|
||||||
|
## Applicative
|
||||||
|
|
||||||
|
Nachdem wir uns letzte Woche ausführlich mit der Typklasse `Functor` beschäftigt haben, bauen wir nun darauf auf und definieren die Applicative-Instanz.
|
||||||
|
Zur Erinnerung:
|
||||||
|
|
||||||
|
class Functor f => Applicative f where
|
||||||
|
pure :: a -> f a
|
||||||
|
<*> :: f (a -> b) -> f a -> f b
|
||||||
|
|
||||||
|
Nehmen sie an, sie hätten folgende Datentypen mit ihren `Functor`-Instanzen gegeben. Schreiben sie jeweils die Applicative-Instanz:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
data Identity a = Identity { unIdentity :: a }
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Functor Identity where
|
||||||
|
fmap f (Identity a) = Identity (f a)
|
||||||
|
|
||||||
|
data Vielleicht a = Etwas a
|
||||||
|
| Nichts
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Functor Vielleicht where
|
||||||
|
fmap f (Etwas a) = Etwas (f a)
|
||||||
|
fmap _ Nichts = Nichts
|
||||||
|
|
||||||
|
data EntwederOder b a = Entweder a
|
||||||
|
| Oder b
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Functor (EntwederOder b) where
|
||||||
|
fmap f (Entweder a) = Entweder (f a)
|
||||||
|
fmap _ (Oder b) = Oder b
|
||||||
|
|
||||||
|
data List a = Cons a (List a)
|
||||||
|
| Nil
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Functor List where
|
||||||
|
fmap f (Cons a r) = Cons (f a) (fmap f r)
|
||||||
|
fmap _ Nil = Nil
|
||||||
|
|
||||||
|
instance Monoid List where
|
||||||
|
mempty = Nil
|
||||||
|
mappend Nil bs = bs
|
||||||
|
mappend (Cons a as) bs = Cons a (mappend as bs)
|
||||||
|
|
||||||
|
data V3 a = V3 a a a
|
||||||
|
|
||||||
|
instance Functor V3 where
|
||||||
|
fmap f (V3 x y z) = V3 (f x) (f y) (f z)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monad
|
||||||
|
|
||||||
|
Zu welchen der oben aufgeführten Typen gibt es eine Monaden-Instanz? Wie sieht diese aus? Schreiben sie diese (falls möglich).
|
||||||
|
|
||||||
|
|
||||||
|
## Bonus
|
||||||
|
|
||||||
|
Seien folgende Funktionen gegeben:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
login :: Maybe Account
|
||||||
|
login = undefined
|
||||||
|
|
||||||
|
getInbox :: Account -> Maybe Inbox
|
||||||
|
getInbox = undefined
|
||||||
|
|
||||||
|
getMails :: Inbox -> [Mail]
|
||||||
|
getMails = undefined
|
||||||
|
|
||||||
|
safeHead :: [a] -> Maybe a
|
||||||
|
safeHead = undefined
|
||||||
|
```
|
||||||
|
|
||||||
|
Schreiben sie eine Funktion:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
getFirstMail :: Maybe Mail
|
||||||
|
```
|
||||||
|
|
||||||
|
welche die oben genannten 4 Funktionen nutzt um die erste Mail aus dem gegebenen Account zurückzuliefern, sofern alles erfolgreich war.
|
||||||
|
|
||||||
|
Können sie beide Varianten (einmal mittels `do`-notation und einmal mit `>>=`) schreiben?
|
BIN
Übungen/Blatt3.pdf
Normal file
BIN
Übungen/Blatt3.pdf
Normal file
Binary file not shown.
155
Übungen/Blatt4.md
Normal file
155
Übungen/Blatt4.md
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
# Übungsblatt 4
|
||||||
|
|
||||||
|
## Vorwort
|
||||||
|
|
||||||
|
Wir haben uns in der vergangenen Vorlesung Parser näher angeschaut. In den praktischen Übungen soll es weniger um das "erfinden" eines neuen Parser-Kombinators gehen, als um die Anwendung.
|
||||||
|
|
||||||
|
## Set-Up
|
||||||
|
|
||||||
|
Da wir nun zum ersten mal mit externen dependencies arbeiten, müssen wir diese zunächst installieren. Dies ist ein sehr wichtiger Schritt, da nahezu alle weiteren Übungszettel dieses Vorgehen voraussetzen.
|
||||||
|
|
||||||
|
Als erstes sollten Sie die Quellen von `stack` mit einem `stack update` aktualisieren. Anschließend erstellen sie ein neues Stack-Projekt mittels `stack new <Projektname>`. Sie erhalten ein Verzeichnis mit dem Projektnamen, in dem ein kleines "Hello World" liegt. Als erstes sollte man immer über die `projektname.cabal` drüber schauen. Hier werden nachher auch alle dependencies eingetragen.
|
||||||
|
|
||||||
|
Bei mir sieht das z.B. so aus (Projekt heisst "parser"):
|
||||||
|
|
||||||
|
```
|
||||||
|
name: parser
|
||||||
|
version: 0.1.0.0
|
||||||
|
synopsis: Initial project template from stack
|
||||||
|
description: Please see README.md
|
||||||
|
homepage: https://github.com/githubuser/parser#readme
|
||||||
|
license: BSD3
|
||||||
|
license-file: LICENSE
|
||||||
|
author: Author name here
|
||||||
|
maintainer: example@example.com
|
||||||
|
copyright: 2016 Author name here
|
||||||
|
category: Web
|
||||||
|
build-type: Simple
|
||||||
|
-- extra-source-files:
|
||||||
|
cabal-version: >=1.10
|
||||||
|
|
||||||
|
library
|
||||||
|
hs-source-dirs: src
|
||||||
|
exposed-modules: Lib
|
||||||
|
build-depends: base >= 4.7 && < 5
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
executable parser-exe
|
||||||
|
hs-source-dirs: app
|
||||||
|
main-is: Main.hs
|
||||||
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||||
|
build-depends: base
|
||||||
|
, parser
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
test-suite parser-test
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
|
hs-source-dirs: test
|
||||||
|
main-is: Spec.hs
|
||||||
|
build-depends: base
|
||||||
|
, parser
|
||||||
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
source-repository head
|
||||||
|
type: git
|
||||||
|
location: https://github.com/githubuser/parser
|
||||||
|
```
|
||||||
|
|
||||||
|
Generell sollte man hier ordentliche Angaben machen, da viele tools dieses automatisch lesen und überall eintragen. Insbesondere sollte man nicht seine private Email-Adresse nehmen, sondern z.b. die Techfak-Adresse, die Studiumsbezogen ist.
|
||||||
|
|
||||||
|
Wir haben hier 3 Bereiche: `library`, `parsers-exe` und `test-suite`. Library ist das, was wir meistens schreiben - eine Sammlung von Funktionen, die das eigentlich tun. Dann haben wir die executable; diese enthält die `main` und ruft meist in wenig Code unsere library auf, nachdem sie z.b. Parameter/Dateien/... gelesen hat und kümmert sich um die Ausgabe. Somit können wir für spätere Zwecke (Projekte) die Library 1:1 wiederverwenden.
|
||||||
|
Die test-suite ignorieren wir für den Moment. Wir kommen in einer separaten Vorlesung noch einmal auf Tests zu sprechen.
|
||||||
|
|
||||||
|
Eine editierte Variante könnte etwa so aussehen:
|
||||||
|
|
||||||
|
```
|
||||||
|
name: parser
|
||||||
|
version: 0.1.0.0
|
||||||
|
synopsis: A little parser for generic CSV-Files
|
||||||
|
description: Please see README.md
|
||||||
|
homepage: https://github.com/Drezil/FFPiHaskell_parser#readme
|
||||||
|
license: BSD3
|
||||||
|
license-file: LICENSE
|
||||||
|
author: Stefan Dresselhaus
|
||||||
|
maintainer: sdressel@techfak.uni-bielefeld.de
|
||||||
|
copyright: 2016 Stefan Dresselhaus
|
||||||
|
category: Tool
|
||||||
|
build-type: Simple
|
||||||
|
-- extra-source-files:
|
||||||
|
cabal-version: >=1.10
|
||||||
|
|
||||||
|
library
|
||||||
|
hs-source-dirs: src
|
||||||
|
exposed-modules: Lib
|
||||||
|
build-depends: base >= 4.7 && < 5
|
||||||
|
, attoparsec
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
executable parser-exe
|
||||||
|
hs-source-dirs: app
|
||||||
|
main-is: Main.hs
|
||||||
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||||
|
build-depends: base
|
||||||
|
, parser
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
test-suite parser-test
|
||||||
|
type: exitcode-stdio-1.0
|
||||||
|
hs-source-dirs: test
|
||||||
|
main-is: Spec.hs
|
||||||
|
build-depends: base
|
||||||
|
, parser
|
||||||
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
source-repository head
|
||||||
|
type: git
|
||||||
|
location: https://github.com/Drezil/FFPiHaskell_parser
|
||||||
|
```
|
||||||
|
|
||||||
|
Änderungen die gemacht wurden:
|
||||||
|
|
||||||
|
- Daten ausgefüllt
|
||||||
|
- attoparsec als dependency der library hinzugefügt
|
||||||
|
- github-links angepasst (sofern man github verwendet)
|
||||||
|
|
||||||
|
Nachdem man das ganze nun gespeichert hat, reicht ein `stack build` um alle dependencies herunterzuladen, kompilieren und installieren. Anschließend kann man mit `stack exec parser-exe` das Programm ausführen.
|
||||||
|
|
||||||
|
## Ein simpler CSV-Parser
|
||||||
|
|
||||||
|
Sie sollten aus ihrem Studium bereits die EBNF kennen. Eine (simple) CSV-Datei besitzt folgende EBNF:
|
||||||
|
|
||||||
|
```
|
||||||
|
csv-file = { row }
|
||||||
|
row = field-list, eol
|
||||||
|
field-list = field, [ ",", field-list ]
|
||||||
|
field = [ whitespace ], field-value, [ whitespace ]
|
||||||
|
field-value = quoted-string | bare-string
|
||||||
|
quoted-string = '"', quoted-content, '"'
|
||||||
|
quoted-content = { quoted-char }
|
||||||
|
quoted-char = (any char except '"' or eol)
|
||||||
|
bare-string = { bare-char }
|
||||||
|
bare-char = (any char except ',' or eol without whitespace at beginning/end)
|
||||||
|
whitespace = space-char, { space-char }
|
||||||
|
space-char = " " | "\t"
|
||||||
|
eol = "\n"
|
||||||
|
```
|
||||||
|
|
||||||
|
Kurzes recap: `{ .. }` bedeutet 1 oder mehr, `[ .. ]` sind optional, `A | B` heißt, entweder A oder B, `A, B, C` bedeutet zunächst A, dann B, dann C.
|
||||||
|
|
||||||
|
### Datenstrukturen
|
||||||
|
|
||||||
|
Überlegen sie sich zunächst, wie eine Datenstruktur aussehen könnte und definieren sie diese. Inhalt sind vorerst nur Strings. Sie brauchen keine Zahlen/Daten/... zu erkennen.
|
||||||
|
|
||||||
|
### Parser
|
||||||
|
|
||||||
|
Schreiben sie einen Parser, der einen CSV-String in diese Datenstruktur parsed und geben sie diese aus (`deriving Show` auf der Datenstruktur reicht). Ein paar Testbeispiele für CSV-Dateien finden sie auf github/im Lernraum.
|
||||||
|
|
||||||
|
### Bonus
|
||||||
|
|
||||||
|
Natürlich ist das nur ein simpler CSV-Parser. Folgende Features wären für einen echten Einsatz noch Wünschenswert:
|
||||||
|
|
||||||
|
- sicherstellen, dass alle "rows" gleich lang sind und ggf. mit Fehlermeldung abbrechen
|
||||||
|
- einen "Header" mit einlesen, der die einzelnen Spalten beschreibt
|
||||||
|
- Quotation nicht nur als "blabla'bla", sondern auch als 'blabla"bla' zulassen, "bla \" bla" auch entsprechend parsen.
|
BIN
Übungen/Blatt4.pdf
Normal file
BIN
Übungen/Blatt4.pdf
Normal file
Binary file not shown.
1001
Übungen/Blatt4_data/CSV_Dummy_hard.csv
Normal file
1001
Übungen/Blatt4_data/CSV_Dummy_hard.csv
Normal file
File diff suppressed because it is too large
Load Diff
11
Übungen/Blatt4_data/CSV_Dummy_problematic.csv
Normal file
11
Übungen/Blatt4_data/CSV_Dummy_problematic.csv
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
first_name,last_name,saying
|
||||||
|
Phillip,Bennett,1
|
||||||
|
Dorothy,Roberts,"<>?:""{}|_+"
|
||||||
|
Walter,Cook,-1.00
|
||||||
|
William,Moreno,̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕
|
||||||
|
Helen,Burke,1
|
||||||
|
Carol,Daniels,⁰⁴⁵
|
||||||
|
Anna,Richards,
|
||||||
|
Wanda,Fox,""""""
|
||||||
|
Anne,Kelley,(。◕ ∀ ◕。)
|
||||||
|
Craig,Armstrong,'
|
|
11
Übungen/Blatt4_data/CSV_Dummy_simple.csv
Normal file
11
Übungen/Blatt4_data/CSV_Dummy_simple.csv
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
first_name,last_name,email,grade
|
||||||
|
Fred,Rivera,frivera0@amazon.co.uk,2.9
|
||||||
|
Wayne,Hansen,whansen1@ucoz.com,1.3
|
||||||
|
Carlos,Edwards,cedwards2@ucla.edu,3.8
|
||||||
|
Benjamin,Reid,breid3@mozilla.com,1.8
|
||||||
|
Susan,Alexander,salexander4@addtoany.com,3.4
|
||||||
|
Philip,Hansen,phansen5@123-reg.co.uk,2.4
|
||||||
|
Jack,Riley,jriley6@gravatar.com,2.6
|
||||||
|
Cynthia,Grant,cgrant7@tmall.com,3.0
|
||||||
|
Patrick,Jenkins,pjenkins8@dagondesign.com,2.4
|
||||||
|
Lori,Davis,ldavis9@patch.com,2.4
|
|
Loading…
Reference in New Issue
Block a user