-- Ü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?
