Merge branch 'master' of github.com:FFPiHaskell/Vorlesung2016

This commit is contained in:
Nicole Dresselhaus 2016-05-14 17:15:59 +02:00
commit 6b48de8bec
13 changed files with 1843 additions and 59 deletions

BIN
Folien/vorlesung4.pdf Normal file

Binary file not shown.

View File

@ -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 = _fun1
fun1 a = a
-- id
fun2 :: a -> b -> a
fun2 = _fun2
fun2 a _ = a
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
```
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 = _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 = _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)
```
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
unPred :: Pred a -> (a -> Bool)
unPred = _unPred
```
-- 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?
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 = _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 = _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
View 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
View 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
View 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
View 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
View 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

Binary file not shown.

155
Übungen/Blatt4.md Normal file
View 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

Binary file not shown.

File diff suppressed because it is too large Load Diff

View 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,'
1 first_name last_name saying
2 Phillip Bennett 1
3 Dorothy Roberts <>?:"{}|_+
4 Walter Cook -1.00
5 William Moreno ̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕
6 Helen Burke 1
7 Carol Daniels ⁰⁴⁵
8 Anna Richards
9 Wanda Fox ""
10 Anne Kelley (。◕ ∀ ◕。)
11 Craig Armstrong '

View 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
1 first_name last_name email grade
2 Fred Rivera frivera0@amazon.co.uk 2.9
3 Wayne Hansen whansen1@ucoz.com 1.3
4 Carlos Edwards cedwards2@ucla.edu 3.8
5 Benjamin Reid breid3@mozilla.com 1.8
6 Susan Alexander salexander4@addtoany.com 3.4
7 Philip Hansen phansen5@123-reg.co.uk 2.4
8 Jack Riley jriley6@gravatar.com 2.6
9 Cynthia Grant cgrant7@tmall.com 3.0
10 Patrick Jenkins pjenkins8@dagondesign.com 2.4
11 Lori Davis ldavis9@patch.com 2.4