diff --git a/coaching/0-intro.md b/coaching/0-intro.md
new file mode 100644
index 0000000000000000000000000000000000000000..d7b7cbb163225f3aad6dc2f6a3579eb5caa7bd35
--- /dev/null
+++ b/coaching/0-intro.md
@@ -0,0 +1,38 @@
+# Hallo!
+
+## Kontakt
+
+Matrix: @eisfunke:eisfunke.com / https://matrix.to/#/@eisfunke:eisfunke.com
+EisfunkeLab-Chatgruppe auf Matrix: #lab:eisfunke.com / https://matrix.to/#/#lab:eisfunke.com
+Mail: nicolas.lenz@udo.edu
+Website: https://www.eisfunke.com
+EisfunkeLab-Newsletter: https://lab.eisfunke.com
+Bytegeschichten: https://bytegeschichten.eisfunke.com
+Meine FuPro-Folien: https://git.eisfunke.com/lab/fupro  (vielleicht hilfreich für die Grundlagen)
+
+Alles auch nochmal auf:
+https://events.eisfunke.com/lab/cfupro21
+
+## Plan
+
+Drei Themenblöcke mit je drei Themen:
+
+- Lambda-Kalkül (Was ist das, Reduktion, Typinferenz)
+- Datentypen: Wie funktioniert das, Listen, Strings, Tupel, Zahlen, Booleans, Maybe, Either und Typvariablen
+- Rekursive Funktionen, Pattern Matching, Bedingungen, wichtige Funktionen
+
+- Typklassen, Kinds, higher-order functions
+- Modellierung mit Datentypen
+- Faltungen und Church-Kodierung
+
+- Listenkomprehensionen
+- Funktoren, Applikative, Monaden, Plusmonaden, bind- und do-Notation
+- Wichtige Monaden: IO, Liste, Leser, Schreiber, Zustand, Zustandstransformer
+
+## Zeitplan
+
+09:00 bis 12:00 Block 1 & 2
+12:00 bis 13:00 Mittagspause
+13:00 bis 15:00 Block 3
+
+**Fragen? Gerne jederzeit!**
diff --git a/coaching/1-1-lambda.md b/coaching/1-1-lambda.md
new file mode 100644
index 0000000000000000000000000000000000000000..247735f5b96d90fd6814b733516d022d02d12ab8
--- /dev/null
+++ b/coaching/1-1-lambda.md
@@ -0,0 +1,115 @@
+# 1.1: Lambda-Kalkül
+
+Was ist das eigentlich?
+
+Eine kleine Einführung im Podcast-Format gibt es hier:
+
+https://bytegeschichten.eisfunke.com/2021/08/17/bg006-lambda-kalkuel/
+(shameless plug)
+
+## Definition
+
+Die Definition von Lambda-Termen als Backus-Naur-Form:
+
+Term ::= x | (Term Term) | λx . Term  (x steht für beliebige Variable)
+
+Beispiele:
+
+- y
+- λz . (x y)
+- (λj . j j) z
+  ~> z z
+- (λx . x) y
+  ~> y
+
+## β-Reduktion
+
+Regeln der Beta-Reduktion:
+
+- (λx.P) Q  -->β  P[x:=Q]
+
+- P  -->β  P'   ==>   P Q  -->β  P' Q
+
+- Q  -->β  Q'   ==>   P Q  -->β  P Q'
+
+- P  -->β  P'   ==>  λx.P  -->β  λx.P'
+
+Bedeutet letztendlich: Argumente in Lambda-Funktionen einsetzen
+
+Wichtig: Verschattung
+
+- (λx.(λx.x)) y  --->β  λx.x
+- (λx.(λx.x)) y  -/->β  λx.y
+
+Wichtig: Umbenennung
+
+- (λx.(λy.x y)) y  --->β  λy.y' y
+- (λx.(λy.x y)) y  -/->β  λy.y y
+
+
+
+## Typinferenz
+
+Die Idee:
+
+λx.x : c -> c
+λy.z : a -> b
+
+
+Die drei Regeln:
+
+----------------------(var)
+ A ∪ {x : τ} |- x : τ
+
+
+ A |- M : σ → τ      A |- N : σ
+---------------------------------(app)
+         A |- (M N) : τ
+
+
+ A ∪ {x : σ} |- M : τ
+----------------------(abs)
+  A |- λx.M : σ → τ
+
+
+Beispiel-Typableitungsbaum für λs . λz . s (s z):
+
+                                               ----------------------------------(var)    ------------------------------(var)
+                                                {s : a -> a, z : a} |- s : a -> a          {s : a -> a, z : a} |- z : a
+----------------------------------(var)        -------------------------------------------------------------------------(app)
+{s : a -> a, z : a} |- s : a -> a                       {s : a -> a, z : a} |- (s z) : a
+--------------------------------------------------------------------------------------------(app)
+                {s : a -> a, z : a} |- s (s z) : a
+            -----------------------------------------(abs)
+              {s : a -> a} |- \z . s (s z) : a -> a
+            -----------------------------------------(abs)
+            _ |- \s . \z . s (s z) : (a -> a) -> a -> a
+
+Beachten: Es kann mehrere gültig ableitbare Typen für einen Term geben!
+
+Z.B. \x.x : a -> a, aber auch \x.x : (a -> a) -> (a -> a)
+
+Es gibt aber auch Terme und Kontexte, für die es keinen gültigen Typen gibt.
+Beispiel: λx.x x
+
+Tipp: Um Schreibarbeit zu sparen, Kontext getrennt definieren
+
+Sei K = {s : a -> a, z : ???}
+
+Zunächst Baum von unten aus aufbauen und die Typen einfach leer lassen
+
+Welche Regel eingesetzt werden muss und wie die Terme aussehen, ist immer eindeutig!
+
+                                      ...
+-----------------(var)       ---------------------(app)
+ K |- s : a -> a                 K |- s z : ???
+----------------------------------------------------------(app)
+        K |- s (s z) : ???
+------------------------------------(abs)
+ {s : a -> a} |- \z . s (s z) : ???
+------------------------------------(abs)
+   _ |- \s . \z . s (s z) : ???
+
+Wenn der Baum fertig aufgebaut ist, Typen erst einsetzen.
+
+Geht ohne den Baum mehrfach zu schreiben und spart Zeit!
diff --git a/coaching/1-2-types.hs b/coaching/1-2-types.hs
new file mode 100644
index 0000000000000000000000000000000000000000..033643b3585acf35a616558de4104b6d7e0c064b
--- /dev/null
+++ b/coaching/1-2-types.hs
@@ -0,0 +1,88 @@
+-- 1.2: Typen
+
+x :: Int
+x = 3
+
+str :: String
+str = "Hallo"
+
+f :: Int -> Int
+f = \x -> x * 2
+
+g :: Int -> Int
+g x = x * 3
+
+-- {g : a -> a} |- λx . g x : a -> a
+
+-- Funktionstypen, Currying
+
+h :: Int -> (Int -> Int)  -- = Int -> Int -> Int
+h = \x -> \y -> x * y
+
+-- h ist die Funktion, die einen Wert x nimmt und eine Funktion zurückgibt,
+-- die einen Wert y nimmt und x * y zurückgibt
+-- h 2 3 ~> 6
+-- Geschachtelte Funktionen funktionieren also wie Funktionen mit mehreren Argumenten
+
+-- h 3 = \y -> 3 * y
+-- h 3 4 = (h 3) 4 = 3 * 4
+
+-- h ist gecurryte Variante von h'
+
+h' :: (Int, Int) -> Int
+h'(x, y) = x * y
+-- nimmt "wirklich" mehrere Argumente als Tupel
+
+-- \x y -> bla ist übrigens nur Syntax für \x -> \y -> bla
+
+-- Strings, Tupel, Zahlen, Booleans, Listen, Maybe, Either
+
+bla :: (Int, String, Int)
+bla = (3, "hallo", 5)
+
+i :: Int -> (Int, Int)
+i x = (x*2, x*3)
+
+b :: Bool
+b = False
+
+xs :: [Int]
+xs = [1,2,3]
+
+ys :: [a]
+ys = []
+
+names :: [String]
+names = ["hallo"]
+
+mx :: Maybe Int
+mx = Nothing
+
+my :: Maybe Int
+my = Just 3
+
+division :: Int -> Int -> Maybe Int
+division = undefined
+
+-- undefined kann zum Testen genutzt werden um eine Funktion noch nicht
+-- implementieren zu müssen, aber die Datei trotzdem kompilierbar zu haben
+
+z :: Int
+z = 3
+
+ex, ey :: Either String Int
+ex = Left "hallo"
+ey = Right 3
+
+division' :: Int -> Int -> Either String Int
+division' = undefined
+
+-- Lässt sich auch schachteln!
+foo :: Either (Either (Either Int String) String) String
+foo = Left (Left (Left 3))
+
+-- Typvariablen
+
+-- a kann jeder Typ sein, aber jeweils bei allen a's der selbe
+myId :: a -> a
+myId x = x
diff --git a/coaching/1-3-functions.hs b/coaching/1-3-functions.hs
new file mode 100644
index 0000000000000000000000000000000000000000..da1a2b0f371effd529e05ebb1fa11ccfcd6d23ed
--- /dev/null
+++ b/coaching/1-3-functions.hs
@@ -0,0 +1,46 @@
+-- 1.3: Funktionen
+
+-- Rekursive Funktionen schreiben
+
+-- Bei Rekursion: Anfangen mit Rekursionabbruch, dem trivialen Fall, also dem Fall für
+-- die leere Liste
+-- Dann Rekursionsschritt
+
+f :: [Int] -> [Int]
+f [] = []
+f (x:xs) = (2*x) : (f xs)
+
+-- Pattern Matching funktioniert von oben nach unten
+-- Versucht Eingabe in die Muster zu "matchen"
+-- Weist dabei Variablen zu
+g :: Maybe Int -> Int
+g (Just 3) = 6
+g (Just 5) = 17
+g (Just x) = x + 3
+g (Just 8) = 4  -- wird nie ausgeführt
+g x = 89
+
+h :: Int -> Int
+h x = if x > 10 then x `div` 2 else x * 2
+
+-- Guards funktionieren wie ein if/ein switch
+-- Wichtig: sie prüfen Bedingungen (Bool-Werte), machen aber kein
+-- Pattern Matching
+i :: Int -> Int
+i x
+    | x > 100 = x `div` 3
+    | x > 10 = x `div` 2
+    | otherwise = 3
+
+foo :: Int -> Int -> Int
+foo = (+)
+
+-- Klammern sparen mit $
+bar, bar' :: Int
+bar = (+) 3 ( (+) 4 5 )
+bar' = (+) 3 $ (+) 4 5
+
+-- . ist die Verkettung/Nacheinanderausführung von rechts nach links
+baz, baz' :: Int
+baz' = (+3) . (+5) . (+8) $ 4
+baz = (+3) ((+5) ((+8) 4))
diff --git a/coaching/1-X-exercises.md b/coaching/1-X-exercises.md
new file mode 100644
index 0000000000000000000000000000000000000000..12ab73403b33a1795faf39f2a9f35cd0baf595fe
--- /dev/null
+++ b/coaching/1-X-exercises.md
@@ -0,0 +1,34 @@
+# 1.X: Übungen zu Block 1
+
+Beantwortet euch Fragen gegenseitig und diskutiert bei Uneinigkeit, was die richtige Antwort ist.
+Antworten einzeln bearbeiten, helft euch gegenseitig bei Problemen und gleicht eure Lösungen ab.
+
+1. Schreibt aus dem Kopf die drei Konstrukte des Lambda-Kalküls und ihre Namen auf. Was sind ihre Bedeutungen?
+
+2. Reduziert folgenden Ausdruck:
+   `((λx. (λy. ((y (λx. (x y))) x) z) ) (x y)) (λx . x)`
+
+3. Leitet den Typ dieses Ausdrucks im Kontext `Γ = {z : a}` her:
+   `λx.λy.x (y z)`
+
+4. Wie muss der Typ `Int -> Int -> Int` geklammert werden?
+
+5. Was ist der Unterschied zwischen den Typen `(Int -> Int) -> Int` und `Int -> (Int -> Int)`?
+   Was bedeuten diese Typen? Was könnten Funktionen mit diesen Typen sein?
+
+6. Was bedeutet der Typ `() -> Int`? Was bedeutet der Typ `Int -> ()`?
+
+7. Wo ist der Unterschied zwischen den Typen `(Int, Int) -> Int` und `Int -> Int -> Int`?
+   Kann man eine Funktion des einen Typens immer in eine des anderen umwandeln? Warum ja / warum nein?
+
+8. Was ist der Unterschied zwischen `Just 3` und `3`? Ist das austauschbar verwendbar?
+
+9. Stellt diesen Ausdruck nur mit Klammern, ohne `.` oder `$` dar:
+    `f . g $ x . y $ z`
+
+10. Schreibt folgende Funktionen als rekursive Funktionen:
+  - `safeHead :: [a] -> Maybe a`
+  - `mapTwiceIfBiggerThanTen :: (Int -> Int) -> [Int] -> [Int]`
+    Wendet die Funktion auf alle Elemente der Liste zweimal an, außer auf Zahlen kleiner als 10, dann nur einmal
+  - `curry' :: ((a, b) -> c) -> (a -> b -> c)`
+  - Denkt euch selber eine Funktion mit den Grunddatentypen aus und implementiert sie!
diff --git a/coaching/1-Y-solutions.md b/coaching/1-Y-solutions.md
new file mode 100644
index 0000000000000000000000000000000000000000..477634ef3cc0b1204fdd3c43144f8563349db5fd
--- /dev/null
+++ b/coaching/1-Y-solutions.md
@@ -0,0 +1,158 @@
+# 1.X: Übungen zu Block 1
+
+Beantwortet euch Fragen gegenseitig und diskutiert bei Uneinigkeit, was die richtige Antwort ist.
+Antworten einzeln bearbeiten, helft euch gegenseitig bei Problemen und gleicht eure Lösungen ab.
+
+1. Schreibt aus dem Kopf die drei Konstrukte des Lambda-Kalküls und ihre Namen auf. Was sind ihre Bedeutungen?
+
+2. Reduziert folgenden Ausdruck:
+   `((λx. (λy. ((y (λx. (x y))) x) z) ) (x y)) (λx . x)`
+
+```
+=  (λx. λy. y (λx. x y) x z ) (x y) (λx . x)  (entklammert)
+~> (λy. y (λx. x y) (x y') z ) (λx . x)
+~> (λx . x) (λx. x (λx . x)) (x y') z
+~> (λx. x (λx . x)) (x y') z
+~> (x y') (λx . x) z
+```
+
+3. Leitet den Typ dieses Ausdrucks im Kontext `Γ = {z : a}` her:
+   `λx.λy.x (y z)`
+
+Erst Baum aufbauen mit Lücken:
+
+```
+Sei K = {z : a, x : ???, y : ???}.
+
+                          -------------- (var)  ------------- (var)
+                           K |- y : ???          K | z : ???
+-------------- (var)      ----------------------------------- (app)
+ K |- x : ???                       K |- y z : ???
+--------------------------------------------------- (app)
+              K |- x (y z) : ???
+--------------------------------------------------- (abs)
+       {z : a, x : ???} |- λy . x (y z) : ???
+      ---------------------------------------- (abs)
+          {z : a} |- λx . λy . x (y z) : ???
+```
+
+Bekannte Typen einsetzen:
+
+```
+Sei K = {z : a, x : ???, y : a -> ???}.
+
+                          ------------------- (var)  ------------ (var)
+                           K |- y : a -> ???          K |- z : a
+-------------- (var)      --------------------------------------- (app)
+ K |- x : ???                       K |- y z : ???
+--------------------------------------------------- (app)
+              K |- x (y z) : ???
+--------------------------------------------------- (abs)
+       {z : a, x : ???} |- λy . x (y z) : ???
+      ---------------------------------------- (abs)
+          {z : a} |- λx . λy . x (y z) : ???
+```
+
+Typen für Lücken nach und nach ausdenken:
+
+```
+Sei K = {z : a, x : b -> ???, y : a -> b}.
+
+                               ----------------- (var)  ------------ (var)
+                                K |- y : a -> b          K |- z : a
+------------------- (var)      ------------------------------------- (app)
+ K |- x : b -> ???                       K |- y z : b
+------------------------------------------------------ (app)
+              K |- x (y z) : ???
+--------------------------------------------------- (abs)
+       {z : a, x : ???} |- λy . x (y z) : ???
+      ---------------------------------------- (abs)
+          {z : a} |- λx . λy . x (y z) : ???
+```
+
+Noch einen Typ ausdenken und zu Ende einsetzen:
+
+```
+Sei K = {z : a, x : b -> c, y : a -> b}.
+
+                               ----------------- (var)  ------------ (var)
+                                K |- y : a -> b          K |- z : a
+----------------- (var)        ------------------------------------- (app)
+ K |- x : b -> c                           K |- y z : b
+---------------------------------------------------------- (app)
+                     K |- x (y z) : c
+---------------------------------------------------------- (abs)
+    {z : a, x : b -> c} |- λy . x (y z) : (a -> b) -> c
+---------------------------------------------------------- (abs)
+ {z : a} |- λx . λy . x (y z) : (b -> c) -> (a -> b) -> c
+```
+
+Der inferierte Typ ist also: `λx . λy . x (y z) : (b -> c) -> (a -> b) -> c`
+
+Oft ist es gar nicht nötig, sich Typen für Variablen auszudenken.
+Setzt zuerst bekannte Typen ein!
+
+4. Wie muss der Typ `Int -> Int -> Int` geklammert werden?
+
+Funktionstypen sind rechtsassoziativ: `Int -> (Int -> Int)`.
+
+5. Was ist der Unterschied zwischen den Typen `(Int -> Int) -> Int` und `Int -> (Int -> Int)`?
+   Was bedeuten diese Typen? Was könnten Funktionen mit diesen Typen sein?
+
+`(Int -> Int) -> Int` sind Funktionen, die eine Funktion `Int -> Int` nehmen und ein `Int`
+zurückgeben.
+Z.B.: `applyToThree f = f 3` mit `applyToThree (+5) ~> 8`.
+
+`Int -> (Int -> Int)` sind Funktionen mit zwei Int-Argumenten (gecurryt).
+Z.B.: `add x y = x + y` mit `add 2 3 ~> 5`.
+
+6. Was bedeutet der Typ `() -> Int`? Was bedeutet der Typ `Int -> ()`?
+
+Eine Funktion `f :: () -> Int` kann nur mit dem einzig möglichen Wert mit dem Typen `()`
+aufgerufen werden: `()`. Es entspricht damit einer Konstante. Man kann sich das auch als
+null-stellige Funktion vorstellen.
+(`() -> c`: nullstellig, `(a) -> c`: einstellig, `(a, b) -> c`: zweistellig, ...)
+
+`Int -> ()` sind Funktionien die immer das selbe zurückgeben: `()`. Letztendlich also Funktionen
+ohne Rückgabe mit dem Platzhalter-Rückgabetypen `()`.
+
+7. Wo ist der Unterschied zwischen den Typen `(Int, Int) -> Int` und `Int -> Int -> Int`?
+   Kann man eine Funktion des einen Typens immer in eine des anderen umwandeln? Warum ja / warum nein?
+
+Beides sind Funktionen mit zwei Ints als Eingabe, aber einmal realisiert durch
+Funktionschachtelung und einmal durch ein Tupel.
+
+Mit `curry`/`uncurry` kann man das ineinander umwandeln, da sie effektiv das gleiche darstellen.
+
+8. Was ist der Unterschied zwischen `Just 3` und `3`? Ist das austauschbar verwendbar?
+
+Das eine ist ein `Maybe Int`, das andere ein `Int`. Damit sind die Werte nicht austauschbar
+verwendbar, weil sie verschiedene Typen haben.
+
+9. Stellt diesen Ausdruck nur mit Klammern, ohne `.` oder `$` dar:
+    `f . g $ x . y $ z`
+
+`f (g (x (y z))`
+
+10. Schreibt folgende Funktionen als rekursive Funktionen:
+  - `safeHead :: [a] -> Maybe a`
+  - `mapTwiceIfBiggerThanTen :: (Int -> Int) -> [Int] -> [Int]`
+    Wendet die Funktion auf alle Elemente der Liste zweimal an, außer auf Zahlen kleiner als 10, dann nur einmal
+  - `curry' :: ((a, b) -> c) -> (a -> b -> c)`
+    (gibt es schon als `curry`, implementiert es selber nochmal!)
+  - Denkt euch selber eine Funktion mit den Grunddatentypen aus und implementiert sie!
+
+```
+safeHead :: [a] -> Maybe a
+safeHead [] = Nothing
+safeHead (x:xs) = Just x
+
+mapTwiceIfBiggerThanTen :: (Int -> Int) -> [Int] -> [Int]
+mapTwiceIfBiggerThanTen f [] = []
+mapTwiceIfBiggerThanTen f (x:xs)
+   | x > 10 = f (f x) : mapTwiceIfBiggerThanTen f xs
+   | otherwise = f x : mapTwiceIfBiggerThanTen f xs
+
+curry' :: ((a, b) -> c) -> (a -> b -> c)
+curry' f x y = f (x, y)
+```
diff --git a/coaching/2-1-advanced-types.hs b/coaching/2-1-advanced-types.hs
new file mode 100644
index 0000000000000000000000000000000000000000..cd2178680ef2bc2a02ca9ba1c3d92d0831fb9885
--- /dev/null
+++ b/coaching/2-1-advanced-types.hs
@@ -0,0 +1,49 @@
+-- 2.1: Fortgeschrittener Typkram
+
+-- Typklassen
+
+-- Nichts mit Klassen aus objektorientierten Sprachen zu tun
+-- Eher wie ein Interface: Garantiert, dass bestimmte Funktionen zur Verfügung stehen
+
+class Maybeable a where
+    intoMaybe :: a -> Maybe a
+
+instance Maybeable Int where
+    intoMaybe 4 = Nothing
+    intoMaybe x = Just x
+
+instance Maybeable [a] where
+    intoMaybe list = Just list
+
+-- a muss Maybeable sein...
+f :: Maybeable a => a -> Maybe a
+f x = intoMaybe x  -- ...deswegen kann ich intoMaybe dadrauf benutzen
+
+-- Einige integrierte Typklassen lassen sich automatisch ableiten, wenn einem die automatische
+-- Version reicht.
+
+data Test = Bla | Blubb String deriving (Show, Eq)
+
+-- Kinds
+
+-- :k Int  "Fertiger Typ"
+-- :k Maybe  "Unfertiger Typ", es fehlt ein Typargument
+-- :k Maybe Int  "Fertiger Typ"
+-- :k Either  "Unfertiger Typ", es fehlen zwei Typargumente
+
+-- Nur fertige Typen können als Typen benutzt werden
+g :: Either String Int -> Maybe Int
+g = undefined
+
+
+-- Higher-order functions
+
+-- Funktionen können Argumente für Funktionen sein!
+
+xs :: [Int]
+xs = map (+3) [1,2,3]
+
+-- map nachimplementieret
+map' :: (Int -> Int) -> [Int] -> [Int]
+map' f [] = []
+map' f (x:xs) = (f x) : map' f xs
diff --git a/coaching/2-2-modelling.hs b/coaching/2-2-modelling.hs
new file mode 100644
index 0000000000000000000000000000000000000000..bc1d1b1759fc121dee615269fe01659f10466965
--- /dev/null
+++ b/coaching/2-2-modelling.hs
@@ -0,0 +1,58 @@
+-- 2.2: Modellieren mit Datentypen
+
+-- Datentypengrundlagen
+
+-- Mehrere Konstruktoren: Alternative, ähnlich Enum
+-- "Summentyp"
+data Color = Red | Green | Blue
+
+data Foo = Foo | Bar
+
+-- Wichtig: Foo ist je nach Kontext Typ oder Konstruktor, das ist aber nicht das selbe
+test :: Foo
+test = Foo
+
+x, y, z :: Color
+x = Red
+y = Green
+z = Blue
+
+-- Konstruktor mit Parametern: Attribute, ähnlich struct
+-- "Produkttyp"
+data Bike = Bike String Color Int
+
+-- In der Form ähnlich zu Tupel:
+-- (String, Color, Int)
+
+-- Summen- und Produkttypen lassen sich kombinieren:
+data User = NormalUser String String | PremiumUser String String Int
+
+-- Teile und Herrsche
+-- Beim Modellieren von Problemen mit Datentypen klein anfangen und erstmal einfache
+-- Sachen in einfachen Typen modellieren
+
+-- Vorhandene Datentypen nutzen (Liste), außer wenn ein eigener Datentyp besser lesbar ist
+-- Z.B. ist Bike oben klarer als einfach das Tupel (String, Color, Int)
+
+-- Records
+
+data Client = Client String String Int deriving Show
+
+-- An sich gleicher Datentyp, aber mit record syntax definiert
+data Client' = Client'
+    { getFirstName :: String
+    , getLastName :: String
+    , getAge :: Int
+    } deriving Show
+
+-- Records können optional zur Definition verwendet werden
+nicolas, nicolas' :: Client'
+nicolas = Client' "Nicolas" "Lenz" 23
+nicolas' = Client' {getFirstName = "Nicolas", getLastName = "Lenz", getAge = 23}
+
+-- Oder zum "updaten" (gibt neuen Wert zurück mit dem entsprechenden Attribut angepasst)
+newNicolas :: Client'
+newNicolas = nicolas {getLastName = "Käsebrot"}
+
+-- Primär sind die records aber Destruktoren: funktionieren wie getter
+-- getLastName nicolas ~> "Lenz"
diff --git a/coaching/2-3-fold.hs b/coaching/2-3-fold.hs
new file mode 100644
index 0000000000000000000000000000000000000000..f6b5dd97e3dd71fbd3a464f75f6a227ad4fbed39
--- /dev/null
+++ b/coaching/2-3-fold.hs
@@ -0,0 +1,217 @@
+-- 2.3: Faltungen und Church-Kodierung
+
+-- Datenstrukturen
+
+{-
+[1,2,3]
+
+Hübsche Syntax für folgendes:
+1:(2:(3:[]))
+
+Das kann man als Baumstruktur darstellen:
+
+  :
+ / \
+1   :
+   / \
+  2   :
+     / \
+    3  []
+-}
+
+-- Funktion, die eine Liste aufsummiert
+sum' :: [Int] -> Int
+sum' [] = 0
+sum' (x:xs) = x + sum' xs
+
+{-
+Was passiert bei sum [1,2,3]?
+
+1 : (2 : (3 : []))
+
+  :
+ / \
+1   :
+   / \
+  2   :
+     / \
+    3  []
+
+wird zu
+
+1 + (2 + (3 + 0))
+
+  +
+ / \
+1   +
+   / \
+  2   +
+     / \
+    3   0
+
+... und das zusammengezogen ergibt 6, die Summe.
+
+-> Die Funktion auf der Liste ersetzt eigentlich nur!
+Alle : durch +
+und alle [] durch 0
+
+Das kann man als Faltung darstellen!
+-}
+
+-- setzt für : immer + ein und für [] 0
+sum'' :: [Int] -> Int
+sum'' = foldr (+) 0
+
+-- Alternativ kann man sich die Faltung vorstellen als auffalten der Liste von rechts
+-- next ist immer das nächste Element, acc (Akkumulator) das bisherige Zwischenergebnis
+sum''' :: [Int] -> Int
+sum''' = foldr (\next acc -> next + acc) 0
+
+-- Macht das gleiche, zwei Richtungen um es gedanklich anzugehen
+-- Versucht beides nachzuvollziehen um zu verstehen, was passiert
+
+-- foldl faltet von links, bzw. es "dreht" den Baum
+-- Siehe: https://en.wikipedia.org/wiki/Fold_(higher-order_function)
+-- foldl (\acc next -> ...) startwert
+
+-- Faltungen funktionieren für alle Datentypen!
+-- Beispieldatentyp aus https://doi.org/10.1145%2F3122955.3122956
+-- Was er bedeutet, ist aber egal für uns jetzt
+
+data Graph a
+   = Empty
+   | Vertex a
+   | Overlay (Graph a) (Graph a)
+   | Connect (Graph a) (Graph a)
+
+-- Faltungsfunktion für Graph
+-- Ein Argument pro Konstruktor ("Interpretation"), und eines für den Wert selber
+-- foldGraph :: () -> () -> () -> () -> Graph a -> b
+foldGraph :: b -> (a -> b) -> (b -> b -> b) -> (b -> b -> b) -> Graph a -> b
+-- dann immer die Interpretationen als Argumente annehmen
+-- Pro Konstruktor ein Fall, den Konstruktor pattern matchen
+-- Dann eigentlich nur die Interpretation einsetzen!
+-- (siehe oben bei Listen, falten ist nur einsetzen!)
+-- Aber bei rekursiven Attributen im Konstruktor rekursiv falten
+foldGraph empty vertex overlay connect (Empty) = empty
+foldGraph empty vertex overlay connect (Vertex x) = vertex x
+foldGraph empty vertex overlay connect (Overlay g1 g2)
+   = overlay
+      (foldGraph empty vertex overlay connect g1)
+      (foldGraph empty vertex overlay connect g2)
+foldGraph empty vertex overlay connect (Connect g1 g2)
+   = connect
+      (foldGraph empty vertex overlay connect g1)
+      (foldGraph empty vertex overlay connect g2)
+
+-- Wie war das bei Listen?
+
+-- Probieren mit diesem Typen
+-- Äquivalent zum integrierten Haskell-Listentyp:
+data List a = Nil | Cons a (List a) deriving Show
+
+foldList :: b -> (a -> b -> b) -> List a -> b
+foldList nil cons (Nil) = nil
+foldList nil cons (Cons x xs) = cons x (foldList nil cons xs)
+
+
+-- Church-Kodierungen
+
+{-
+Im Lambda-Kalkül gibt es keine Zahlen, Listen und Datentypen.
+Wie Werte darstellen?
+
+Idee: Wir stellen einen Wert dar als Funktion, die ihn faltet
+
+Dafür müssen wir den Wert niemals konkret niederschreiben! Das geht also auch im reinen
+Lambda-Kalkül.
+-}
+
+-- [1,2,3] als Haskell-Liste
+eins2dreiH :: [Int]
+eins2dreiH = 1 : (2 : (3 : []))
+
+-- faltet die Liste [1,2,3] mit foldr
+eins2dreiHC :: (Int -> b -> b) -> b -> b
+eins2dreiHC cons nil = foldr cons nil [1,2,3]
+
+-- faltet auch die Liste [1,2,3], aber die Liste wird nie konkret aufgeschrieben
+-- Quasi fold ausgerechnet
+eins2dreiC :: (Int -> b -> b) -> b -> b
+eins2dreiC cons nil = cons 1 (cons 2 (cons 3 nil))
+
+-- Das kann ich nun also auch im reinen Lambda-Kalkül darstellen!
+-- (bis auf die Zahlen, die wir der Einfachheit jetzt nicht auch church-kodieren)
+eins2drei :: (Int -> b -> b) -> b -> b
+eins2drei = \c n -> c 1 (c 2 (c 3 n))
+-- λc. λn. c 1 (c 2 (c 3 n))
+
+-- Und das ist die Church-Kodierung für die Liste [1,2,3]
+-- Damit kann ich dann weiterrechnen wie mit einer Haskell-Liste, aber im reinen Lambda-Kalkül
+-- Ich kann also ganz normale Listenfunktionen schreiben, aber nur mit Lambda-Termen
+-- Church-Kodierungen ermöglicht also Listen darzustellen im reinen Lambda-Kalkül
+
+-- Konkateniert zwei Haskell-Listen mit fold
+concatF :: [Int] -> [Int] -> [Int]
+-- concatF l1 l2 = l1 ++ l2
+concatF l1 l2 = foldr (:) l2 l1
+
+-- Parallel dazu: Konkateniert zwei church-kodierte Listen
+-- foldr ... ... l1 entspricht l1 ... ...
+-- denn l1 ist ja church-kodiert und damit die Funktion, die l1 faltet
+-- (:) ist church-kodiert c (cons)
+concatC :: ((Int -> b -> b) -> b -> b) -> ((Int -> b -> b) -> b -> b) -> ((Int -> b -> b) -> b -> b)
+concatC = \l1 l2 -> \c n -> l1 c (l2 c n)
+
+{-
+Probieren wir nochmal die Church-Kodierung mit dem Falten aus:
+
+eins2drei: Funktion mit Argumenten c und n, gibt zurück:
+
+eins2drei c n:
+  c
+ / \
+1   c
+   / \
+  2   c
+     / \
+    3   n
+
+Oh!
+Setzen wir (:) für c und [] für n ein!
+
+eins2drei (:) [] ~>
+  :
+ / \
+1   :
+   / \
+  2   :
+     / \
+    3  []
+
+Innerhalb von Haskell lässt sich die Church-kodierte Liste so also wieder in eine Haskell-Liste
+übersetzen: wir setzen die Konstruktoren ein!
+
+Haskell-interne Liste: foldr (+) 0 (1:(2:(3:[]))) ~> 6
+Lambda-kodierte Liste: eins2drei (+) 0
+
+  +
+ / \
+1   +
+   / \
+  2   +
+     / \
+    3   0
+
+Im Lambda-Kalkül gibt es nur Funktionen, Variablen, Funktionsanwendungen.
+Wie Liste darstellen?
+
+=> Mit Funktion, die die "gedachte" Liste auswertet!
+
+Lambda-Church-Encoding stellt Datenstruktur quasi als ihre Faltungsfunktion dar
+
+In Haskell haben wir konkrete Listendatenstrukturen, eben die Haskell-Listen, durch einsetzen der Konstruktoren in die Lambda-kodierte Liste können wir
+aus der abstrakten "gedachte Liste dargestellt als Funktion die sie faltet" eine konkrete Haskell-Datenstruktur machen.
+
+Tipp: Das geht für alle Datenstrukturen, die sich als so ein rekursive Baumstruktur mit verschiedenen Knotenarten darstellen lassen
+-}
diff --git a/coaching/2-X-exercises.md b/coaching/2-X-exercises.md
new file mode 100644
index 0000000000000000000000000000000000000000..c54d5d3ee0c0f639c0db8df367304111a02cc488
--- /dev/null
+++ b/coaching/2-X-exercises.md
@@ -0,0 +1,46 @@
+# 2.X: Übungen zu Block 2
+
+1. Erstellt eine Typklasse `Doubleable` für Typen, die verdoppelt werden können.
+
+2. Instanziiert `Doubleable` für `Int` und `[a]`.
+
+3. Modelliert folgendes Szenario mit passenden Haskell-Datentypen:
+
+   Ein Geschäft besteht aus Abteilungen.
+
+   Jede Abteilung hat eine Manager'in und Mitarbeiter'innen,
+   die jeweils einen Namen und eine Adresse haben.
+
+   In den Abteilungen werden Produkte verkauft, die einen Namen und einen Preis haben.
+
+   Außerdem soll gespeichert werden, ob auf ein Produkt der normale oder der reduzierte
+   Mehrwertsteuersatz erhoben wird.
+
+   Verwendet deriving um die Typen anzeig- und vergleichbar zu machen.
+   Vergleicht eure Lösungen und diskutiert, was die sinnvollste Modellierung ist.
+
+4. Schreibt eine Funktion, die alle Preise des Geschäfts um 10\% erhöht.
+
+Gegeben sei folgender Datentyp:
+
+`data Something a = Foo a | Bar Bool (Something a) | Baz (Something a) (Something a)`
+
+5. Welchen Kind hat `Something`?
+
+6. Erstellt zwei nicht-triviale Beispielinstanzen von `Something Int` und `Something String`.
+
+7. Instanziiert die Typklassen `Show` und `Eq` für `Something` manuell.
+
+8. Schreibt die Faltungsfunktion `foldSomething`. Beginnt mit der Typdeklaration.
+
+9. Verwendet `foldSomething` um eine Funktion zu schreiben, die alle `Int`s in `Foo`s in einem
+   `Something Int` aufaddiert.
+
+   Schreibt die selbe Funktion auch nochmal als rekursive Funktion mit Pattern Matching.
+   Vergleicht die Implementationen und überlegt, wie sie zusammenhängen und wie sie sich ineinander
+   übersetzen lassen
+
+10. Erstellt die Church-Kodierung eurer `Something`-Beispielinstanzen als Haskell-Lambda-Ausdrücke.
+    Lasst der Einfachheit halber die a's und Bools unkodiert.
+
+11. Erstellt die Church-Kodierung der Konstruktoren `Foo`, `Bar` und `Baz` von Something.
diff --git a/coaching/2-Y-solutions.md b/coaching/2-Y-solutions.md
new file mode 100644
index 0000000000000000000000000000000000000000..d92bfb779b4c8139d0bb582743c663093b97b15e
--- /dev/null
+++ b/coaching/2-Y-solutions.md
@@ -0,0 +1,152 @@
+# 2.X: Übungen zu Block 2
+
+1. Erstellt eine Typklasse `Doubleable` für Typen, die verdoppelt werden können.
+
+```
+class Doubleable a where
+   double :: a -> a
+```
+
+2. Instanziiert `Doubleable` für `Int` und `[a]`.
+
+```
+instance Doubleable Int where
+   double x = 2 * x
+
+instance Doubleable [a] where
+   double str = str ++ str
+```
+
+3. Modelliert folgendes Szenario mit passenden Haskell-Datentypen:
+
+   Ein Geschäft besteht aus Abteilungen.
+
+   Jede Abteilung hat eine Manager'in und Mitarbeiter'innen,
+   die jeweils einen Namen und eine Adresse haben.
+
+   In den Abteilungen werden Produkte verkauft, die einen Namen und einen Preis haben.
+
+   Außerdem soll gespeichert werden, ob auf ein Produkt der normale oder der reduzierte
+   Mehrwertsteuersatz erhoben wird.
+
+   Verwendet deriving um die Typen anzeig- und vergleichbar zu machen.
+   Vergleicht eure Lösungen und diskutiert, was die sinnvollste Modellierung ist.
+
+```
+data TaxRate = Normal | Reduced
+
+data Product = Product
+   { productName :: String
+   , productPrice :: Int  -- Cent, Fließkommazahlen vermeiden wenn möglich wegen Ungenauigkeit
+   }
+
+data Person = Person
+   { personName :: String
+   , personAddress :: String
+   }
+
+data Section = Section
+   { sectionManager :: Person
+   , sectionEmployees :: [Person]
+   , sectionProducts :: [Product]
+   }
+
+data Store = Store
+   { storeSections :: [Section]
+   }
+```
+
+4. Schreibt eine Funktion, die alle Preise des Geschäfts um 10\% erhöht.
+
+```
+increasePrice :: Store -> Store
+increasePrice (Store sections) = Store $ map increasePriceSection sections where
+   increasePriceSection section
+      = section {sectionProducts = map increasePriceProduct (sectionProducts section)}
+   increasePriceProduct (Product name price) = Product name (floor $ fromIntegral price * 1.1)
+```
+
+Gegeben sei folgender Datentyp:
+
+`data Something a = Foo a | Bar Bool (Something a) | Baz (Something a) (Something a)`
+
+5. Welchen Kind hat `Something`?
+
+`* -> *`
+
+6. Erstellt zwei nicht-triviale Beispielinstanzen von `Something Int` und `Something String`.
+
+```
+something1 :: Something Int
+something1 = Bar True (Foo 3)
+
+something2 :: Something String
+something2 = Baz (Foo "hello") (Foo "bye") :: Something String
+```
+
+7. Instanziiert die Typklassen `Show` und `Eq` für `Something` manuell.
+
+```
+instance Show a => Show (Something a) where
+   show (Foo x) = unwords ["Foo", show x]
+   show (Bar b s) = unwords ["Bar", show b, "("++ show s ++ ")"]
+   show (Baz s1 s2) = unwords ["Baz", "("++ show s1 ++ ")", "("++ show s2 ++ ")"]
+```
+
+8. Schreibt die Faltungsfunktion `foldSomething`. Beginnt mit der Typdeklaration.
+
+```
+foldSomething :: (a -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> Something a -> b
+foldSomething foo bar baz (Foo x) = foo x
+foldSomething foo bar baz (Bar b s) = bar b (foldSomething foo bar baz s)
+foldSomething foo bar baz (Baz s1 s2) = baz
+   (foldSomething foo bar baz s1)
+   (foldSomething foo bar baz s2)
+```
+
+9. Verwendet `foldSomething` um eine Funktion zu schreiben, die alle `Int`s in `Foo`s in einem
+   `Something Int` aufaddiert.
+
+   Schreibt die selbe Funktion auch nochmal als rekursive Funktion mit Pattern Matching.
+   Vergleicht die Implementationen und überlegt, wie sie zusammenhängen und wie sie sich ineinander
+   übersetzen lassen
+
+```
+sumSomething :: Something Int -> Int
+sumSomething = foldSomething
+   (\x -> x)
+   (\b acc -> acc)
+   (\acc1 acc2 -> acc1 + acc2)
+```
+
+10. Erstellt die Church-Kodierung eurer `Something`-Beispielinstanzen als Haskell-Lambda-Ausdrücke.
+    Lasst der Einfachheit halber die a's und Bools unkodiert.
+
+```
+something1C :: (Int -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> b
+something1C = \foo bar baz -> bar True (foo 3)
+
+something2C :: (String -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> b
+something2C = \foo bar baz -> baz (foo "hello") (foo "bye")
+```
+
+11. Erstellt die Church-Kodierung der Konstruktoren `Foo`, `Bar` und `Baz` von Something.
+
+```
+foo
+   :: a  -- x
+   -> (a -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> b
+foo = \x -> \foo bar baz -> foo x
+
+bar
+   :: Bool  -- b
+   -> ((a -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> b)  -- s
+   -> (a -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> b
+bar = \b s -> \foo bar baz -> bar b (s foo bar baz)
+
+baz
+   :: ((a -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> b)  -- s1
+   -> ((a -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> b)  -- s2
+   -> (a -> b) -> (Bool -> b -> b) -> (b -> b -> b) -> b
+baz = \s1 s2 -> \foo bar baz -> baz (s1 foo bar baz) (s1 foo bar baz)
+```
diff --git a/coaching/3-1-list-comprehension.hs b/coaching/3-1-list-comprehension.hs
new file mode 100644
index 0000000000000000000000000000000000000000..60f8173f3a14e8231da97b0efbcab1b433ede404
--- /dev/null
+++ b/coaching/3-1-list-comprehension.hs
@@ -0,0 +1,11 @@
+-- 3.1: Listenkomprehension
+
+-- [Rückgabe | Variable <- Generator, Bedingungen]
+
+-- {(x,y,z) | x,y,z ∈ ℕ, 5x + 3y² + 10 = z}
+sol :: [(Int, Int, Int)]
+sol = [(x,y,z) | z <- [0..], x <- [0..z], y <- [0..z], (5*x + 3*y^2 + 10) == z]
+-- Nur erster Generator darf unendlich sein, sonst wird der erste nie weitergezählt!
+
+foo :: [Int]
+foo = [x + y | x <- [0,1,2,3], y <- [0,1,2,3], x == y]
diff --git a/coaching/3-2-boxes.hs b/coaching/3-2-boxes.hs
new file mode 100644
index 0000000000000000000000000000000000000000..96dd85e1eceb3ecc011ca51717d958bd201108a2
--- /dev/null
+++ b/coaching/3-2-boxes.hs
@@ -0,0 +1,121 @@
+-- 3.2: Boxen
+
+-- Die verschiedenen Arten an Typklassen, die man sich als "Boxen" vorstellen kann,
+-- die zur Monade führen
+
+import Control.Monad
+
+-- Funktoren
+
+-- Boxen, in denen man Funktionen mappen kann
+
+x :: [Int]
+x = fmap (+3) [1,2,3]  -- für Listen ist fmap = map
+
+y :: Maybe Int
+y = fmap (+3) (Just 3)
+
+y' :: Maybe Int
+y' = (+3) <$> Just 3  -- <$> ist Infix-Version von fmap
+
+
+-- Applikative
+
+-- Funktionen in der Box kann man auf Werte in der Box anwenden
+
+z :: [Int]
+z = [(+1), (+2)] <*> [1,2,3]
+
+foo :: Maybe Int
+foo = Just (+1) <*> Just 5
+
+-- Kann man auch nutzen, um mehrstellige Funktionen zu mappen
+
+mapMultiple :: [Int]
+mapMultiple = (+) <$> [1,2,3] <*> [4,5,6]
+
+
+-- Monaden
+
+-- Boxen, die man auspacken kann und mit dem ausgepackten arbeiten kann, sofern man es anschließend
+-- wieder einpackt
+
+-- Es wirkt magisch, aber letztendlich nur: >>= = concatMap
+
+bar :: [Int]
+bar = [1,2,3] >>= (\x -> [x -x])
+
+bar' :: [Int]
+bar' = concatMap (\x -> [x, -x]) [1,2,3]
+
+-- return packt etwas möglichs einfach in die Monade ein
+baz :: [Int]
+baz = return 3
+
+-- Komprehension, bind- und do-Notation lassen sich ineinander übersetzen, nur verschiedene
+-- Syntaxen, selbe Bedeutung
+
+test :: [(Int, Int, Int)]
+test = [(x,y,z) | z <- [0..], x <- [0..z], y <- [0..z]]
+
+testBind :: [(Int, Int, Int)]
+testBind =
+    [0..] >>= \z ->
+    [0..z] >>= \x ->
+    [0..z] >>= \y ->
+    return (x,y,z)
+
+testDo :: [(Int, Int, Int)]
+testDo = do
+    z <- [0..]
+    x <- [0..z]
+    y <- [0..z]
+    return (x,y,z)
+
+-- Möglicherweise Listenmonade besser verständlich wenn man die Parallele von der Listen-
+-- komperehnsion bedenkt
+
+
+-- Plusmonaden
+
+-- Die haben auch noch mzero (null, neutrales Element) und mplus (Addition)
+
+-- Für Listen ist mzero die leere Liste
+bla :: [Int]
+bla = mzero
+
+-- Für Listen ist mplus die Konkatenation
+blubb :: [Int]
+blubb = [1,2,3] `mplus` [4,5,6]
+
+-- Dank Plusmonaden funktionieren Bedinungen/guards
+
+sol :: [(Int, Int, Int)]
+sol = [(x,y,z) | z <- [0..], x <- [0..z], y <- [0..z], (5*x + 3*y^2 + 10) == z]
+
+solDo :: [(Int, Int, Int)]
+solDo = do
+    z <- [0..]
+    x <- [0..z]
+    y <- [0..z]
+    guard ((5*x + 3*y^2 + 10) == z)
+    return (x,y,z)
+
+-- guard :: Bool -> [()]
+
+-- guard gibt bei nicht erfüllter Bedingung mzero zurück
+-- Bei Listen also []
+-- Und wenn man in der Listenkomprehension irgendwo bla <- [] hat, geht das halt nicht weiter!
+-- Bei erfüllter Bedingung [()], und bla <- [()] macht alles nachfolgende einfach einmal, ändert
+-- also nichts.
+
+blabbDo = do
+    _ <- []
+    return 3
+
+-- Zuweisungen können ausgelassen werden:
+-- _ <- bla entspricht bla
+-- bla >>= \_ -> blubb entspricht bla >> blubb
+
+blabbBind :: [Int]
+blabbBind = [1,2,3] >> return 3
diff --git a/coaching/3-3-monads.hs b/coaching/3-3-monads.hs
new file mode 100644
index 0000000000000000000000000000000000000000..fe1505dd27acdc732ed11d64411c8adc9cee879e
--- /dev/null
+++ b/coaching/3-3-monads.hs
@@ -0,0 +1,111 @@
+-- 3.3: Wichtige Monaden
+
+import Control.Monad
+
+-- List (siehe 3.2)
+
+-- Maybe (siehe auch 3.2)
+
+-- Ermöglicht fehlerbehaftete Berechnungen zu kombinieren
+-- Wenn man irgendwo Nothing entpackt, kommt insgesamt Nothing raus
+
+-- safeDivide :: Int -> Int -> Maybe Int
+
+x :: Maybe Int
+x = do
+    x <- Just 3  -- safeDivide 9 3
+    y <- Nothing
+    return (x + y)
+
+-- Either
+
+-- Wie Maybe, aber Left ist eine Fehlermeldung
+
+-- IO
+
+-- IO Bla ist eine Ein-Ausgabe-Operation mit Rückgabetyp Bla
+-- Z.B. getLine kann dann monadisch ausgepackt werden
+
+main :: IO ()
+main = do
+    name <- getLine
+    putStrLn $ "Hallo " ++ name
+
+-- Leser
+
+-- Ermöglicht es aus einem impliziten Kontext zu lesen
+
+data Context = Foo String Int
+
+test :: Context -> String
+test (Foo s i) = s
+
+bla :: Context -> Int
+bla (Foo s i) = i
+
+bar :: Int -> Context -> Int
+bar i = do
+    t <- test
+    b <- bla
+    return (b+i)
+
+baz :: Int -> Context -> Int
+baz i (Foo t b) = b + i
+
+-- Schreiber
+
+-- Ermöglicht es in einen impliziten Kontext zu schreiben, z.B. Lognachrichten
+
+logMsg :: String -> (String, ())
+logMsg str = (str, ())
+
+something :: Int -> (String, Int)
+something n = do
+    logMsg "Ich logge was\n"
+    logMsg "Sicherheitshalber noch was loggen\n"
+    return (n*2)
+
+-- Zustand
+
+-- Ermöglicht es, aus einem impliziten Kontext zu lesen und zu schreiben
+-- Impliziter Zustand!
+
+newtype Zustand z a = Zs {ausf :: z -> (z, a)}
+-- ausf ist Zustandsübergangsfunktion:
+-- nimmt den alten Zustand und gibt den neuen Zustand und eine Rückgabe zurück
+
+instance Functor (Zustand z) where
+  fmap f zs = Zs (\s -> let (s', a) = ausf zs s in (s', f a))
+
+instance Applicative (Zustand z) where
+  pure = return
+  zf <*> za = zf >>= \f -> za >>= \a -> return (f a)
+
+instance Monad (Zustand z) where
+  return x = Zs (\ s -> (s, x))
+  (Zs p) >>= f =
+    Zs (\s -> let {(s', y) = p s; (Zs q) = f y} in q s')
+
+-- Zustand ist ein Int, diese Funktion gettet den Zustand und hat daher
+-- den monadischen Rückgabetypen Int
+getZustand :: Zustand Int Int
+getZustand = Zs $ \z -> (z, z)
+
+-- Zustand ist ein Int, diese Funktion settet nur und hat daher nur ()
+-- als Platzhalter als monadischen Rückgabetypen
+setZustand :: Int -> Zustand Int ()
+setZustand newZ = Zs $ \z -> (newZ, ())
+
+-- getZustand >>= \x -> ...
+
+-- Kann man kombinieren
+
+blablubb :: Zustand Int Int
+blablubb = do
+    x <- getZustand
+    setZustand 6
+    setZustand (x + 1)
+    return 7
+
+-- Zustandstransformer ist hauptsächlich wie Zustand, kann aber failen weil es Maybe
+-- in der Zustandsübergangsfunktion hat
diff --git a/coaching/3-X-exercises.md b/coaching/3-X-exercises.md
new file mode 100644
index 0000000000000000000000000000000000000000..918ee400129cdd3b395484af7a2d7ce4bc720ad9
--- /dev/null
+++ b/coaching/3-X-exercises.md
@@ -0,0 +1,128 @@
+# 3.X: Übungen zu Block 3
+
+```
+import Control.Monad  -- für guard
+```
+1. Definiert die unendliche Liste aller Tripel `(x,y,z)` mit `1*x = 2*y = 3*z`. Verwendet eine
+  Listenkomprehension. Stelle sie dann auch in der do- und bind-Notation dar.
+
+2. Schreibe eine Funktion `[Int] -> [Int]`, die alle Elemente der Eingabeliste verdoppelt.
+   Schreibe die Funktion einmal mit einer Listenkomprehension und einmal mit map.
+
+3. Schreibe eine Funktion `[Int] -> [Int]`, die nur die Elemente der Eingabeliste, die größer als 10
+   sind, beibehält — einmal als Listenkomprehension, einmal mit filter.
+
+Gegeben sei folgender Datentyp:
+
+`data List a = Nil | Cons a (List a)`
+
+4. Erstelle eine Beispielinstanz von List Int.
+
+5. Instanziiere Functor für List.
+
+6. Instanziiere Applicative für List.
+
+7. Instanziiere Monad für List.
+
+8. Instanziiere MonadPlus für List.
+
+9. Verwendet fmap/<$> um die Funktion (*2) auf eure Beispielliste zu mappen.
+
+10. Verwendet <*> um eine Liste von Funktionen auf eure Beispielliste zu applizieren
+
+11. Verwende <$> und <*> um `(+)` auf zwei Listen zu applizieren.
+
+12. Verwendet die do-Notation, um die Listenkomprehension aus der ersten Aufgabe auf unseren
+    Listentypen zu übertragen. Warum benötigt es dafür die MonadPlus-Instanz?
+
+MonadPlus wird benötigt, damit mzero zur Verfügung steht, das von guard benutzt wird um die
+monadische Berechnung "abzubrechen".
+
+13. Schreibt die Funktionen `safeLogarithm, safeDivide, safeSqrt :: Float -> Either String Float`,
+    die jeweils den natürlichen Logarithmus, die Quadratwurzel und den Kehrwert berechnen bzw.
+    eine sinnvolle Fehlermeldung ausgeben. Erstellt eine Funktion, die diese Funktionen nacheinander
+    auf einen Wert anwendet.
+    Macht das jeweils einmal mit Pattern Matching, der do-Notation und der bind-Notation.
+
+Gegeben sei folgender Datentyp, der die Infos über den Aufruf einer Webseite enthält:
+
+`data Context = Context {contextTime :: String, contextIP :: String, contextPath :: String}`
+
+14. Schreibt eine Funktion String -> Context -> String, die den Eingabestring zweimal hintereinander
+    zurückgibt, wenn der Path "/double" ist, ansonsten den String unverändert lässt. Verwendet dabei
+    die Lesermonade.
+
+Gegeben sei folgende Funktion:
+
+```
+collatz :: Int -> Int
+collatz n
+  | even n = n `div` 2
+  | otherwise = 3*n + 1
+```
+
+(Das Collatz-Problem ist ein sehr spannendes ungelöstes Problem der Mathematik! Schaut euch mal
+https://www.youtube.com/watch?v=094y1Z2wpJg an, wenn ihr Lust habt.)
+
+15. Schreibe eine Funktion logMsg :: String -> (String, ()), die einen beliebigen String loggt.
+
+16. Schreibe collatz in collatzLog :: Int -> (String, Int) um, das zusätzlich die vorgenommene
+    Operation loggt.
+
+Gegeben sei die Zustandsmonade:
+
+```
+newtype Zustand z a = Zs {ausf :: z -> (z, a)}
+
+instance Functor (Zustand z) where
+  fmap f zs = Zs (\s -> let (s', a) = ausf zs s in (s', f a))
+
+instance Applicative (Zustand z) where
+  pure = return
+  zf <*> za = zf >>= \f -> za >>= \a -> return (f a)
+
+instance Monad (Zustand z) where
+  return x = Zs ( \ s -> (s, x) )
+  (Zs p) >>= f =
+    Zs (\s -> let {(s', y) = p s; (Zs q) = f y} in q s')
+```
+
+17. Erklärt euch gegenseitig die Bedeutung von z und a.
+
+Wir wollen nun mit einem Stack arbeiten: Der Zustand ist `[Int]`, das erste Element der Liste ist
+das oberste Element auf dem Stack.
+
+18. Schreibe die monadischen Funktionen `push` und `pop`, die ein Element auf den Stack pushen bzw.
+    das oberste Element entfernen und zurückgeben. `pop` sollte dafür monadisch ein Maybe Int zurück-
+    geben, damit Nothing zurückgegeben werden kann, falls der Stack leer ist.
+
+19. Schreibe eine zustandsmonadische Funktion die das oberste Element des Stacks verdoppelt.
+
+Gegeben sei die Zustandstransformer-Monade:
+
+```
+newtype ZustandsTransf s a = ZT {appZT :: s -> Maybe(s, a)}
+
+instance Functor (ZustandsTransf s) where
+  fmap f (ZT g) = ZT (\s -> case g s of
+    Nothing -> Nothing
+    Just (s, y) -> Just(s, f y))
+
+instance Applicative (ZustandsTransf s) where
+  pure = \x -> ZT (\s -> Just(s, x))
+  (ZT f) <*> (ZT g) = ZT(\s -> case f s of
+    Nothing -> Nothing
+    Just(s', h) -> case g s' of
+      Nothing -> Nothing
+      Just(s'', x) -> Just(s'', h x))
+
+instance Monad (ZustandsTransf s) where
+  return x = ZT (\s -> Just(s, x))
+  (ZT p) >>= f = ZT (\s0 -> case p s0 of
+    Just(s1, x) -> let (ZT q) = f x in q s1
+    Nothing -> Nothing)
+```
+
+20. Erklärt euch den Unterschied zwischen Zustand und ZustandsTransf.
+
+21. Schreibt eure zustandsmonadischen Funktionen für ZustandsTransf um.
diff --git a/coaching/3-Y-solutions.md b/coaching/3-Y-solutions.md
new file mode 100644
index 0000000000000000000000000000000000000000..cc4560bcb9336d9098854bb9c939a674ae62a201
--- /dev/null
+++ b/coaching/3-Y-solutions.md
@@ -0,0 +1,228 @@
+# 3.X: Übungen zu Block 3
+
+```
+import Control.Monad  -- für guard
+```
+
+1. Definiert die unendliche Liste aller Tripel `(x,y,z)` mit `1*x = 2*y = 3*z`. Verwendet eine
+  Listenkomprehension. Stelle sie dann auch in der do- und bind-Notation dar.
+
+```
+listL :: [(Int, Int, Int)]
+listL = [(x,y,z) | z <- [0..], x <- [0..z], y <- [0..z], 1*x == 2*y, 2*y == 3*z]
+
+listD :: [(Int, Int, Int)]
+listD = do
+    z <- [0..]
+    x <- [0..z]
+    y <- [0..z]
+    guard $ 1*x == 2*y
+    guard $ 2*y == 3*z
+    return (x, y, z)
+
+listB :: [(Int, Int, Int)]
+listB =
+  [0..] >>= \z ->
+  [0..z] >>= \x ->
+  [0..z] >>= \y ->
+  guard (1*x == 2*y) >>
+  guard (2*y == 3*z) >>
+  return (x, y, z)
+```
+
+2. Schreibe eine Funktion `[Int] -> [Int]`, die alle Elemente der Eingabeliste verdoppelt.
+   Schreibe die Funktion einmal mit einer Listenkomprehension und einmal mit map.
+
+```
+doubleList, doubleList' :: [Int] -> [Int]
+doubleList xs = [2*x | x <- xs]
+doubleList' = map (2*)
+```
+
+3. Schreibe eine Funktion `[Int] -> [Int]`, die nur die Elemente der Eingabeliste, die größer als 10
+   sind, beibehält — einmal als Listenkomprehension, einmal mit filter.
+
+```
+greaterThan10, greaterThan10' :: [Int] -> [Int]
+greaterThan10 xs = [x | x <- xs, x > 10]
+greaterThan10' = filter (>10)
+```
+
+Gegeben sei folgender Datentyp:
+
+`data List a = Nil | Cons a (List a)`
+
+4. Erstelle eine Beispielinstanz von List Int.
+
+```
+exampleList :: List Int
+exampleList = Cons 1 $ Cons 2 $ Cons 3 Nil
+```
+
+5. Instanziiere Functor für List.
+
+*Überprüft eure Implementation selber, indem ihr sie mit der eingebauten Haskell-Liste vergleicht.*
+
+6. Instanziiere Applicative für List.
+
+*Überprüft eure Implementation selber, indem ihr sie mit der eingebauten Haskell-Liste vergleicht.*
+
+7. Instanziiere Monad für List.
+
+*Überprüft eure Implementation selber, indem ihr sie mit der eingebauten Haskell-Liste vergleicht.*
+
+8. Instanziiere MonadPlus für List.
+
+*Überprüft eure Implementation selber, indem ihr sie mit der eingebauten Haskell-Liste vergleicht.*
+
+9. Verwendet fmap/<$> um die Funktion (*2) auf eure Beispielliste zu mappen.
+
+*Überprüft eure Implementation selber, indem ihr sie mit der eingebauten Haskell-Liste vergleicht.*
+
+10. Verwendet <*> um eine Liste von Funktionen auf eure Beispielliste zu applizieren
+
+*Überprüft eure Implementation selber, indem ihr sie mit der eingebauten Haskell-Liste vergleicht.*
+
+11. Verwende <$> und <*> um `(+)` auf zwei Listen zu applizieren.
+
+*Überprüft eure Implementation selber, indem ihr sie mit der eingebauten Haskell-Liste vergleicht.*
+
+12. Verwendet die do-Notation, um die Listenkomprehension aus der ersten Aufgabe auf unseren
+    Listentypen zu übertragen. Warum benötigt es dafür die MonadPlus-Instanz?
+
+*Überprüft eure Implementation selber, indem ihr sie mit der eingebauten Haskell-Liste vergleicht.*
+
+MonadPlus wird benötigt, damit mzero zur Verfügung steht, das von guard benutzt wird um die
+monadische Berechnung "abzubrechen".
+
+13. Schreibt die Funktionen `safeLogarithm, safeDivide, safeSqrt :: Float -> Either String Float`,
+    die jeweils den natürlichen Logarithmus, die Quadratwurzel und den Kehrwert berechnen bzw.
+    eine sinnvolle Fehlermeldung ausgeben. Erstellt eine Funktion, die diese Funktionen nacheinander
+    auf einen Wert anwendet.
+    Macht das jeweils einmal mit Pattern Matching, der do-Notation und der bind-Notation.
+
+Gegeben sei folgender Datentyp, der die Infos über den Aufruf einer Webseite enthält:
+
+`data Context = Context {contextTime :: String, contextIP :: String, contextPath :: String}`
+
+14. Schreibt eine Funktion String -> Context -> String, die den Eingabestring zweimal hintereinander
+    zurückgibt, wenn der Path "/double" ist, ansonsten den String unverändert lässt. Verwendet dabei
+    die Lesermonade.
+
+```
+f :: String -> Context -> String
+f input = do
+  path <- contextPath
+  if path == "/double"
+    then return (input ++ input)
+    else return input
+```
+
+Gegeben sei folgende Funktion:
+
+```
+collatz :: Int -> Int
+collatz n
+  | even n = n `div` 2
+  | otherwise = 3*n + 1
+```
+
+(Das Collatz-Problem ist ein sehr spannendes ungelöstes Problem der Mathematik! Schaut euch mal
+https://www.youtube.com/watch?v=094y1Z2wpJg an, wenn ihr Lust habt.)
+
+15. Schreibe eine Funktion logMsg :: String -> (String, ()), die einen beliebigen String loggt.
+
+```
+logMsg :: String -> (String, ())
+logMsg str = (str, ())
+```
+
+16. Schreibe collatz in collatzLog :: Int -> (String, Int) um, das zusätzlich die vorgenommene
+    Operation loggt.
+
+```
+collatzLog :: Int -> (String, Int)
+collatzLog n
+  | even n = logMsg "even" >> return (n `div` 2)
+  | otherwise = logMsg "odd" >> return (3*n + 1)
+```
+
+Gegeben sei die Zustandsmonade:
+
+```
+newtype Zustand z a = Zs {ausf :: z -> (z, a)}
+
+instance Functor (Zustand z) where
+  fmap f zs = Zs (\s -> let (s', a) = ausf zs s in (s', f a))
+
+instance Applicative (Zustand z) where
+  pure = return
+  zf <*> za = zf >>= \f -> za >>= \a -> return (f a)
+
+instance Monad (Zustand z) where
+  return x = Zs ( \ s -> (s, x) )
+  (Zs p) >>= f =
+    Zs (\s -> let {(s', y) = p s; (Zs q) = f y} in q s')
+```
+
+17. Erklärt euch gegenseitig die Bedeutung von z und a.
+
+z ist der Typ des Zustandswertes, a ist der monadische Rückgabewert der Zustandsoperation.
+
+Wir wollen mit einem Stack arbeiten: Der Zustand ist `[Int]`, das erste Element der Liste ist das
+oberste Element auf dem Stack.
+
+18. Schreibe die monadischen Funktionen `push` und `pop`, die ein Element auf den Stack pushen bzw.
+    das oberste Element entfernen und zurückgeben. `pop` sollte dafür monadisch ein Maybe Int zurück-
+    geben, damit Nothing zurückgegeben werden kann, falls der Stack leer ist.
+
+```
+push :: Int -> Zustand [Int] ()
+push x = Zs $ \stack -> (x:stack, ())
+
+pop :: Zustand [Int] (Maybe Int)
+pop = Zs f where
+  f [] = ([], Nothing)
+  f (x:xs) = (xs, Just x)
+```
+
+19. Schreibe eine zustandsmonadische Funktion die das oberste Element des Stacks verdoppelt.
+
+```
+double :: Zustand [Int] ()
+double = do
+  mx <- pop
+  case mx of
+    Nothing -> return ()
+    Just x -> do
+      push (x * 2)
+```
+
+Gegeben sei die Zustandstransformer-Monade:
+
+```
+newtype ZustandsTransf s a = ZT {appZT :: s -> Maybe(s, a)}
+
+instance Functor (ZustandsTransf s) where
+  fmap f (ZT g) = ZT (\s -> case g s of
+    Nothing -> Nothing
+    Just (s, y) -> Just(s, f y))
+
+instance Applicative (ZustandsTransf s) where
+  pure = \x -> ZT (\s -> Just(s, x))
+  (ZT f) <*> (ZT g) = ZT(\s -> case f s of
+    Nothing -> Nothing
+    Just(s', h) -> case g s' of
+      Nothing -> Nothing
+      Just(s'', x) -> Just(s'', h x))
+
+instance Monad (ZustandsTransf s) where
+  return x = ZT (\s -> Just(s, x))
+  (ZT p) >>= f = ZT (\s0 -> case p s0 of
+    Just(s1, x) -> let (ZT q) = f x in q s1
+    Nothing -> Nothing)
+```
+
+20. Erklärt euch den Unterschied zwischen Zustand und ZustandsTransf.
+
+21. Schreibt eure zustandsmonadischen Funktionen für ZustandsTransf um.
diff --git a/coaching/4-outro.md b/coaching/4-outro.md
new file mode 100644
index 0000000000000000000000000000000000000000..e7c6751a933fd3d1ad4d1be201eb22e7b8590546
--- /dev/null
+++ b/coaching/4-outro.md
@@ -0,0 +1,45 @@
+# Danke!
+
+## Feedback
+
+Ihr bekommt bald eine Mail mit einer Einladung zu einer anonymen Feedback-Umfrage.
+Bitte nehmt teil! Vielen Dank!
+
+Außerdem werde ich das Material veröffentlichen und euch den Link dazu schicken.
+Im Anschluss werde ich eure persönlichen Daten von meinem Server löschen.
+
+Weiteres Feedback ist auch sehr gerne willkommen! Hilfe ist auch gern gesehen.
+
+Falls ihr Lust habt, schreibt mir gerne nach der Klausur mal, wie es gelaufen ist.
+
+EisfunkeLab-Newsletter: lab.eisfunke.com
+
+## Mich unterstützen
+
+Mehr davon, und noch viel mehr? Z.B. Haskell in der Praxis?
+
+Ihr könnt mir helfen mit Feedback, Werbung, Mitmachen oder natürlich mit...:
+
+Überweisung: Nicolas Lenz, IBAN: DE46 4306 0967 1089 7106 00, BIC: GENODEM1GLS
+(für mich gebührenfrei, nicht anonym, bevorzugt)
+
+PayPal: https://paypal.me/eisfunke
+(für mich gebührenfrei, nicht anonym)
+
+LiberaPay: https://liberapay.com/Eisfunke/
+(kostet mich Gebühren, anonym)
+
+Vielen Dank!
+
+## Kontakt
+
+Matrix: @eisfunke:eisfunke.com / https://matrix.to/#/@eisfunke:eisfunke.com
+EisfunkeLab-Chatgruppe auf Matrix: #lab:eisfunke.com / https://matrix.to/#/#lab:eisfunke.com
+Mail: nicolas.lenz@udo.edu
+Website: https://www.eisfunke.com
+EisfunkeLab-Newsletter: https://lab.eisfunke.com
+Bytegeschichten: https://bytegeschichten.eisfunke.com
+Meine FuPro-Folien: https://git.eisfunke.com/lab/fupro
+
+Alles auch nochmal auf:
+https://events.eisfunke.com/lab/cfupro21