summaryrefslogtreecommitdiff
path: root/ws2015
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2016-01-13 18:18:06 +0100
committerGregor Kleen <gkleen@yggdrasil.li>2016-01-13 18:18:06 +0100
commita6f85b9b8894a7817baad1a5e850366d02eb197a (patch)
treef69bcd4f2e72cb85825459a8df0b4e84faef8bf7 /ws2015
parente621ada27e4eb7b4495416a59741893a6003a20f (diff)
downloaduni-a6f85b9b8894a7817baad1a5e850366d02eb197a.tar
uni-a6f85b9b8894a7817baad1a5e850366d02eb197a.tar.gz
uni-a6f85b9b8894a7817baad1a5e850366d02eb197a.tar.bz2
uni-a6f85b9b8894a7817baad1a5e850366d02eb197a.tar.xz
uni-a6f85b9b8894a7817baad1a5e850366d02eb197a.zip
FFP 11.1
Diffstat (limited to 'ws2015')
-rw-r--r--ws2015/ffp/blaetter/11/FFP_U11-1_GADTs.hs115
-rw-r--r--ws2015/ffp/blaetter/11/FFP_U11-2_Yesod.hs85
-rw-r--r--ws2015/ffp/blaetter/11/FFP_U11-3_Yesod.hs145
-rw-r--r--ws2015/ffp/blaetter/11/FFP_U11-4_TemplateHaskell.hs65
-rw-r--r--ws2015/ffp/blaetter/11/GameUnits.hs76
5 files changed, 486 insertions, 0 deletions
diff --git a/ws2015/ffp/blaetter/11/FFP_U11-1_GADTs.hs b/ws2015/ffp/blaetter/11/FFP_U11-1_GADTs.hs
new file mode 100644
index 0000000..495e4c5
--- /dev/null
+++ b/ws2015/ffp/blaetter/11/FFP_U11-1_GADTs.hs
@@ -0,0 +1,115 @@
1-- Fortgeschrittene Funktionale Programmierung,
2-- LMU, TCS, Wintersemester 2015/16
3-- Steffen Jost, Alexander Isenko
4--
5-- Übungsblatt 11. 13.01.2016
6--
7-- Thema: GADTs, Yesod-Formulare
8--
9-- Hinweis:
10-- Für Übung A11-2 und A11-3 benötigen Sie die Yesod-Bibliothek.
11-- Hinweise zur Installation mit Stack finden sich in den Folien
12-- und auf Alexander's githup Seite:
13-- https://github.com/cirquit/ffp-lib
14--
15-- Die Aufgaben A11-2 und A11-3 finden Sie in separaten, beiligenden Dateien.
16-- Dies ist notwendig, weil sich sonst das von Yesod verwendete TemplateHaskell
17-- in die Quere kommt.
18
19{-# LANGUAGE GADTs #-}
20
21module Main where
22
23
24main :: IO ()
25main = main_A11_1
26
27
28
29-- A11-1 GADTs
30--
31-- Ein beliebtes Beispiel für die Mächtigkeit von GADTs ist ein Datentyp
32-- zur sicheren Verwendung von head und tail auf Listen.
33--
34-- Betrachten Sie dazu folgende Datentypdeklarationen,
35-- bei denen einen Listentyp SList a b deklariert wird,
36-- dessen zweites Typargument protokolliert, ob die Liste
37-- leer ist oder nicht:
38
39-- We should call these "Z" and "S", they're peano naturals.
40data Empty = Empty
41data NonEmpty a = NonEmpty
42
43data SList a b where
44 Nil :: SList a Empty
45 Cons :: a -> SList a b -> SList a (NonEmpty b)
46
47list0 :: SList Int Empty
48list0 = Nil
49
50list1 :: SList Int (NonEmpty (NonEmpty Empty))
51list1 = Cons 42 (Cons 69 list0)
52
53safeHead :: SList a (NonEmpty b) -> a
54safeHead (Cons x _) = x
55
56main_A11_1 :: IO ()
57main_A11_1 = do
58 putStrLn "Hallo zur Übung 10!"
59 -- print $ safeHead list0 -- Zeile 1: liefert Typfehler beim Kompilieren!
60 print $ safeHead list1 -- Zeile 2: sollte funktionieren
61 print $ safeHead $ safeTail list1 -- Zeile 3: sollte funktionieren
62 -- print $ safeHead $ safeTail $ safeTail list1 -- Zeile 4: sollte Typfehler beim Kompilieren liefern!
63
64-- a) Machen Sie als Aufwärmübung den Datentyp SList
65-- zu einer Instanz der Typklasse Show.
66-- Zur vereinfachten Behandlung der Klammerung geben wir die Listen so aus:
67-- > list0
68-- []
69-- > list1
70-- 42:69:[]
71
72
73instance Show a => Show (SList a b) where
74 showsPrec _ Nil = showString "[]"
75 showsPrec d (Cons a as) = showParen (d > 10) $ showsPrec (10 + 1) a . showString ":" . showsPrec (10 + 1) as
76
77
78-- b) Geben Sie den Typ von list1 explizit an!
79
80
81-- !!! TODO !!! Typangabe
82
83
84-- c) Wie wir mit Zeile 1 von main_A11_1 überprüfen können,
85-- wird eine Aufruf von safeHead auf eine leere Liste
86-- bereits während der Kompilation von der Typprüfung verhindert!
87--
88-- Probieren Sie dies durch Entfernen der Kommentare in Zeile 1 von main_A11_1 aus,
89-- und schauen Sie sich die Fehlermeldung an. Was passiert hier?
90--
91-- Warum würde eine Datentypdeklaration wie
92-- data IsEmpty a = Empty | NonEmpty a
93-- anstatt von Empty und NonEmpty hier nicht weiterhelfen?
94
95
96{-
97A type like IsEmpty carries the sought after distinction at value level -- ordinary lists do so as well.
98-}
99
100
101-- d) Deklarieren Sie eine Funktion safeTail,
102-- welche einer SList den Kopf entfernt.
103-- Achten Sie dabei auf die korrekte Typsignatur!
104-- Wenn Sie es richtig gemacht haben, dann sollte die
105-- 3. Zeile von main_A11_1 sollte nun funktionieren
106-- 4. Zeile von main_A11_1 einen Typfehler beim Kompilieren liefern
107
108safeTail :: SList a (NonEmpty b) -> SList a b
109safeTail (Cons _ l) = l
110
111
112
113--
114-- Weiter geht es mit der Datei FFP_U11-2_Yesod.hs
115--
diff --git a/ws2015/ffp/blaetter/11/FFP_U11-2_Yesod.hs b/ws2015/ffp/blaetter/11/FFP_U11-2_Yesod.hs
new file mode 100644
index 0000000..83f7945
--- /dev/null
+++ b/ws2015/ffp/blaetter/11/FFP_U11-2_Yesod.hs
@@ -0,0 +1,85 @@
1-- Fortgeschrittene Funktionale Programmierung,
2-- LMU, TCS, Wintersemester 2015/16
3-- Steffen Jost, Alexander Isenko
4--
5-- Übungsblatt 11. 13.01.2016
6--
7-- Teilaufgabe
8-- A11-2 Yesod Grundlagen (Routing & Handling)
9--
10
11{-# LANGUAGE ViewPatterns #-}
12{-# LANGUAGE MultiParamTypeClasses #-}
13{-# LANGUAGE OverloadedStrings #-}
14{-# LANGUAGE TypeFamilies #-}
15{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
16
17module Main where
18
19import Yesod
20import qualified Data.Text as T
21
22{-
23 Ausgehend von dem minimalen Yesod Beispielen auf Folie 09-12,
24 erstellen Sie eine kleine Webseite mit Yesod, welche Integer-Zahlen
25 addieren und multiplizieren kann.
26 Zur Übung der Grundlagen des Routings möchten wir dies
27 unsinnigerweise über die URL-Pfade der Webseite machen:
28
29 * http://localhost:3000/24/plus/373/ist
30 zeigt eine Seite an, welche die Zahl 397 anzeigt.
31
32 * http://localhost:3000/5/mal/-13/ist
33 zeigt eine Seite an, welche die Zahl -65 anzeigt.
34
35 * http://localhost:3000/5/plus/-1foo3/ist
36 zeigt eine Hilfseite an, welche darauf hinweist, dass nur ganze Zahlen erlaubt sind.
37
38 * jeder unsinniger Pfad wie etwa
39 http://localhost:3000/5/foo/-13/ist
40 zeigt eine Hilfseite an, die sagt welche Rechenoperationen erlaubt sind.
41
42
43 Hinweis: Yesod verwendet Data.Text, ein effizienter Ersatz für den ineffizienten Typ String.
44 Modul Data.Text stellt Methoden zur Bearbeitung von Werte dieses Typs bereit, hier eine Auswahl davon:
45 pack :: String -> Text
46 unpack :: Text -> String
47 append :: Text -> Text -> Text
48 strip :: Text -> Text
49 null :: Text -> Bool
50 length :: Text -> Int
51-}
52
53
54{- LÖSUNGSVORSCHLAG -}
55
56main :: IO ()
57main = warp 3000 CalcApp
58
59data CalcApp = CalcApp
60
61instance Yesod CalcApp
62
63mkYesod "CalcApp" [parseRoutes|
64 / HomeR GET
65|]
66
67
68getHomeR :: Handler Html
69getHomeR = defaultLayout $ do
70 setTitle "Hello!"
71 let x = 2
72 let y = 3
73 toWidget [whamlet|
74 <h2>Hello World!
75 <p> Some text that is <i>displayed</i> here.
76 <p> We have #{show x}+#{show y}=#{show $ x + y}!
77 |]
78
79
80
81
82
83--
84-- Weiter geht es mit der Datei FFP_U11-3_Yesod.hs
85--
diff --git a/ws2015/ffp/blaetter/11/FFP_U11-3_Yesod.hs b/ws2015/ffp/blaetter/11/FFP_U11-3_Yesod.hs
new file mode 100644
index 0000000..badd9e0
--- /dev/null
+++ b/ws2015/ffp/blaetter/11/FFP_U11-3_Yesod.hs
@@ -0,0 +1,145 @@
1-- Fortgeschrittene Funktionale Programmierung,
2-- LMU, TCS, Wintersemester 2015/16
3-- Steffen Jost, Alexander Isenko
4--
5-- Übungsblatt 11. 13.01.2016
6--
7-- Teilaufgabe
8-- A11-3 Yesod: Applikative Formulare
9--
10-- Betrachten Sie das Beispiel aus der Vorlesung zu applikativen Formularen.
11-- Der Code ist hier vollständig enthalten und sollte problemlos ausführbar sein.
12
13-- a)
14-- Erweiteren Sie diese Webapplikation um eine Seite, auf der ein Benutzer
15-- mit einem Formular zur Eingabe einer positiven ganzen Zahl auffordert.
16-- Der Benutzer wird ggf. solange erneut aufgefordert, bis eine positive ganze Zahl ermittelt wurde;
17-- danach wird die Zahl einfach auf dem Bildschirm ausgegeben.
18
19
20
21-- b)
22-- Erweitern Sie Ihr Programm aus der vorherigen Teilausgabe, so dass
23-- je nach der eingegebenen Zahl ein Formular zur Eingabe dieser Anzahl
24-- an Autos (gemäß dem Beispiel) abgefragt werden.
25--
26-- Nutzen Sie dazu die Möglichkeit zur Kombination mehrerer Formulare in Yesod!
27-- Auch für 5 Autos soll nur ein einziges Formular mit einem einzelnen Absenden-Knopf
28-- angzeigt werden, welches entsprechend viele Felder für 5 Autos enthält.
29--
30-- Nach dem Absenden des Formulares, sollen die eingegebenen Autos einfach nur
31-- auf dem Bildschrim dargestellt werden.
32--
33-- Ein Beispiel zur Kombination zweier Formulare zu einem einzigen Formular:
34--
35-- twoCarAForm :: AForm Handler (Car,Car)
36-- twoCarAForm = (,) <$> carAForm <*> carAForm
37--
38
39
40{-# LANGUAGE GADTs #-}
41{-# LANGUAGE ViewPatterns #-}
42{-# LANGUAGE MultiParamTypeClasses #-}
43{-# LANGUAGE OverloadedStrings #-}
44{-# LANGUAGE TypeFamilies #-}
45{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
46
47
48import Yesod
49import Data.Text
50import Control.Applicative
51import Yesod.Form
52
53
54{- LÖSUNGSVORSCHLAG -}
55
56main :: IO ()
57main = warp 3000 CarApp
58
59
60data CarApp = CarApp
61
62instance Yesod CarApp
63
64instance RenderMessage CarApp FormMessage where
65 renderMessage _ _ = defaultFormMessage
66
67mkYesod "CarApp" [parseRoutes|
68/ HomeR
69/car/#Int CarR
70|]
71
72
73
74data Car = Car { carModel :: Text
75 , carYear :: Int
76 , carColor :: Maybe Text
77 }
78 deriving Show
79
80carAForm :: AForm Handler Car
81carAForm = Car
82 <$> areq textField "Model" Nothing
83 <*> areq intField "Year" (Just 1996)
84 <*> aopt textField "Color" Nothing
85
86carForm :: Html -> MForm Handler (FormResult Car, Widget)
87carForm = renderBootstrap2 carAForm
88
89-- Beispiel zur Kombination zweier applikativer Formulare zu einem:
90twoCarAForm :: AForm Handler (Car,Car)
91twoCarAForm = (,) <$> carAForm <*> carAForm
92
93
94handleHomeR :: Handler Html
95handleHomeR = redirect $ CarR 3
96
97
98handleCarR :: Int -> Handler Html
99handleCarR n = do
100 ((result,widget), enctype) <- runFormPost $ carForm
101 case result of
102 FormMissing -> defaultLayout $ do
103 setTitle "Form Demo"
104 [whamlet|
105 <h2>Form Demo
106 <form method=post action=@{CarR n} enctype=#{enctype}>
107 ^{widget}
108 <button>Submit
109 |]
110
111 FormSuccess car -> defaultLayout $ do
112 setTitle "Form Auswerten"
113 [whamlet|
114 <h2>#{n} Cars should have been received:
115 <ul>
116 $forall acar <- [car]
117 <li>#{show acar}
118 <p>
119 <a href=@{HomeR}>Zurück
120 |]
121
122 _ -> defaultLayout [whamlet|
123 <h2>Fehler!
124 <p>Bitte nochmal eingeben:
125 <form method=post action=@{CarR n} enctype=#{enctype}>
126 ^{widget}
127 <button>Abschicken
128 |]
129 -- das gemeinsame hamlet-widget bei
130 -- FormMissing und FormFailure text
131 -- kann man natürlich auch nur einmal
132 -- in einer lokalen Variable definieren
133
134
135
136
137
138
139--
140-- Weiter geht es mit der Datei FFP_U11-4_TemplateHaskell.hs
141--
142
143
144
145
diff --git a/ws2015/ffp/blaetter/11/FFP_U11-4_TemplateHaskell.hs b/ws2015/ffp/blaetter/11/FFP_U11-4_TemplateHaskell.hs
new file mode 100644
index 0000000..05668a7
--- /dev/null
+++ b/ws2015/ffp/blaetter/11/FFP_U11-4_TemplateHaskell.hs
@@ -0,0 +1,65 @@
1-- Fortgeschrittene Funktionale Programmierung,
2-- LMU, TCS, Wintersemester 2015/16
3-- Steffen Jost, Alexander Isenko
4--
5-- Übungsblatt 11. 13.01.2016
6--
7-- Teilaufgabe
8-- A11-4a TemplateHaskell
9--
10-- Im Modul GameUnits sind einige
11-- Kreaturen definiert, und eine Funktion,
12-- um zwei gegeneinander Kämpfen zu lassen,
13-- wie in Übungsblatt 7 bereits verwendet.
14--
15-- Es ist nervig, jedes Mal die komplette Figur einzugeben,
16-- weshalb wir Konstanten definieren möchten, etwa so:
17{-
18units =
19 [ unit{ name = "Scout", str= 5 }
20 , unit{ name = "Crow", str= 5, hit=1, flyer=True }
21 , unit{ name = "Orc", str=20, hit=1 }
22 ]
23
24scout = units !! 0
25crow = units !! 1
26orc = units !! 2
27-}
28
29-- Es ist jedoch schwierig, dies konsistent zu halten!
30-- Schreiben Sie innerhalb des Moduls GameUnit eine
31-- Funktion, welche die entsprechende Konstanten-Deklaration
32-- für alle Einheiten der stockUnitList automatisch generiert,
33-- so dass der folgende Code danach funktioniert!
34
35-- Hinweis: Dazu benötigen Sie vermutlich
36-- aus Modul Language.Haskell.TH folgende Definitionen
37-- ValD, VarP, NormalB, newName und QuasiQuoting
38--
39
40{-# LANGUAGE TemplateHaskell #-}
41
42
43import GameUnits
44
45
46$(stockUnitShortcuts)
47
48
49main = do
50 dobattle orc elf
51 dobattle orc elf
52 dobattle elf dwarf
53 dobattle elf dwarf
54 dobattle elf dwarf
55 dobattle elf dwarf
56
57
58
59dobattle :: Unit -> Unit -> IO ()
60dobattle att def = do
61 putStrLn $ "Attacker: " ++ name att
62 putStrLn $ "Defender: " ++ name def
63 winner <- battle att def
64 putStrLn $ "Winner: " ++ show winner
65 putStrLn "---" \ No newline at end of file
diff --git a/ws2015/ffp/blaetter/11/GameUnits.hs b/ws2015/ffp/blaetter/11/GameUnits.hs
new file mode 100644
index 0000000..a47614e
--- /dev/null
+++ b/ws2015/ffp/blaetter/11/GameUnits.hs
@@ -0,0 +1,76 @@
1-- Fortgeschrittene Funktionale Programmierung,
2-- LMU, TCS, Wintersemester 2015/16
3-- Steffen Jost, Alexander Isenko
4--
5-- Übungsblatt 11. 13.01.2016
6--
7-- Teilaufgabe
8-- A11-4b TemplateHaskell
9
10{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
11
12module GameUnits where
13
14
15import Data.Char
16import System.Random
17import Language.Haskell.TH
18
19uncapitalize :: String -> String
20uncapitalize (c:s) = (toLower c):s
21uncapitalize [] = []
22
23---------------------------
24-- Datatype Declarations --
25---------------------------
26
27data Unit = Unit {str, hit :: Int, flyer :: Bool, name :: String }
28 deriving (Eq, Show)
29type Units = [Unit]
30
31unit :: Unit -- default Value
32unit = Unit {str=undefined, hit=2, flyer=False, name=undefined }
33
34takeHit :: Unit -> Unit
35takeHit monster = monster { hit = hit monster - 1 }
36
37isDead :: Unit -> Bool
38isDead Unit { hit=n } = n <= 0
39
40----------------------------------
41-- Some Stock Units in the game --
42----------------------------------
43stockUnitList :: [Unit]
44stockUnitList =
45 [ unit{ name = "Scout", str= 5 }
46 , unit{ name = "Crow", str= 5, hit=1, flyer=True }
47 , unit{ name = "Orc", str=20, hit=1 }
48 , unit{ name = "Dwarf", str=15, hit=2 }
49 , unit{ name = "Elf", str=30, hit=1 }
50 , unit{ name = "Giant", str=20, hit=4 }
51 , unit{ name = "Knight",str=35, hit=2 }
52 , unit{ name = "Dragon",str=55, hit=3, flyer=True }
53 ]
54
55
56battle :: Unit -> Unit -> IO Unit
57battle att def = do
58 attRoll <- randomRIO (0,99)
59 defRoll <- randomRIO (0,99)
60 case (attRoll < str att, defRoll < str def) of
61 (True, False) -> check att $ takeHit def
62 (False,True ) -> check (takeHit att) def
63 _other -> battle att def -- reroll
64 where
65 check a d
66 | isDead a = return d
67 | isDead d = return a
68 | otherwise = battle a d
69
70
71
72stockUnitShortcuts :: Q [Dec]
73-- declares a constants of type Unit for each unit on the
74stockUnitShortcuts = undefined -- !!! TODO !!!
75
76 \ No newline at end of file