Revert "Added Aufgabe 4"

This reverts commit aab564e716.
This commit is contained in:
Yannick Gottschalk 2017-04-30 23:45:31 +02:00
parent aab564e716
commit 22717263bb
25 changed files with 1164 additions and 287 deletions

29
.ghci
View File

@ -1,29 +0,0 @@
:def vis \_ -> return $ "GHC.Vis.vis"
:def mvis \_ -> return $ "GHC.Vis.mvis"
:def svis \_ -> return $ "GHC.Vis.svis"
:def view \x -> return $ "GHC.Vis.view (" ++ x ++ ") " ++ show x
:def eval \x -> return $ "GHC.Vis.eval \"" ++ x ++ "\""
:def switch \_ -> return $ "GHC.Vis.switch"
:def update \_ -> return $ "GHC.Vis.update"
:def clear \_ -> return $ "GHC.Vis.clear"
:def restore \_ -> return $ "GHC.Vis.restore"
:def timeBack \_ -> return $ "GHC.Vis.history (+1)"
:def timeForward \_ -> return $ "GHC.Vis.history (\\x -> x - 1)"
:def export \x -> return $ "GHC.Vis.export " ++ show x
:def setDepth \x -> return $ "GHC.Vis.setDepth (" ++ x ++ ")"
-- Evaluate one step and update values in ghc-vis
:def su \x -> return $ ":step " ++ x ++ "\n:update"
-- Continue to next breakpoint and update values in ghc-vis
:def cu \_ -> return $ ":continue\n:update"
-- Keep evaluating and updating on any key pressed, quit with q
:def asu \x -> getChar >>= \c -> case c of { 'q' -> return ""; _ -> return $ ":step " ++ x ++ "\n:update\n:asu" }
-- :tsu t x
-- Evaluate one step of expression x every t seconds until any key is pressed
:def tsu \x -> (System.Timeout.timeout (round $ 1000000 * (read . head $ words x :: Double)) getChar) >>= \c -> case c of { Just _ -> return ""; _ -> return $ ":step " ++ (unwords . tail $ words x) ++ "\n:update\n:tsu " ++ (head $ words x) }
:set -fobject-code

6
app/Aufgabe1Main.hs Normal file
View File

@ -0,0 +1,6 @@
module Main where
import Aufgabe1
main :: IO ()
main = putStrLn result

6
app/Aufgabe2Main.hs Normal file
View File

@ -0,0 +1,6 @@
module Main where
import Aufgabe2
main :: IO ()
main = putStrLn result

6
app/Aufgabe3Main.hs Normal file
View File

@ -0,0 +1,6 @@
module Main where
import Aufgabe3
main :: IO ()
main = putStrLn result

View File

@ -1,2 +0,0 @@
tar xf /media/remote/ygottschalk/.stack.tar.gz -C $HOME/

27
src/AreaCode.hs Normal file
View File

@ -0,0 +1,27 @@
module AreaCode (AreaCode,separateAreaCode) where
import qualified Data.Attoparsec.Text as A
import Data.Attoparsec.Combinator
import qualified Data.Text as T
type Number = String
type Name = String
type AreaCode = String
{-Area Code Parser-}
separateAreaCode :: Number -> (AreaCode,Number)
separateAreaCode nr =
case A.parse parseAreaCode (T.pack nr) of
A.Done s ac -> (ac, T.unpack s)
_ -> ("",nr)
parseAreaCode :: A.Parser String
parseAreaCode = do
many' (A.char ' ')
A.char '('
ac <- many1 $ A.satisfy (A.inClass "0123456789")
A.char ')'
many' (A.char ' ')
return ac

82
src/Aufgabe1.hs Normal file
View File

@ -0,0 +1,82 @@
-- Aufgabe 1
-- =========
module Aufgabe1 where
-- Functional phone book Implementieren Sie ein Telefonbuch als Funktion.
type Number = String
type Name = String
type Entry = [Number]
newtype PhoneBook = PB (Name -> Entry)
-- Implementieren Sie die Funktion `usePB`, welche aus einem `PhoneBook`
-- mit einem `Name` den zugehörigen `Entry` findet`
usePB :: PhoneBook -> Name -> Entry
usePB = undefined
-- Implementieren Sie eine `Monoid` Instanz für `PhoneBook`, um zu garantieren,
-- dass `PhoneBook` ein leeres Element hat und eine Verkettungsfunktion, die
-- zwei `PhoneBook`s in eines zusammenführt.
instance Monoid PhoneBook where
mempty = undefined
mappend = undefined
-- Implementieren Sie eine Funktion `addEntry`, welche einem `PhoneBook` eine
-- `Name` zu `Number` Verknüpfung hinzufügt, also für einen gegebenen Namen und
-- eine Nummer einen Eintrag im Telefonbuch erstellt.
addEntry :: Name -> Number -> PhoneBook -> PhoneBook
addEntry = undefined
-- Implementieren Sie eine Funktion `delEntry`, die alle Nummern aus dem `PhoneBook`
-- entfernt, die mit dem gegebenen `Name` assoziiert sind.
-- Hinweis: "Entfernt" heißt streng genommen nur, dass die Nummern nicht mehr aus
-- dem resultierenden Telefonbuch herausgesucht werden können
delEntry :: Name -> PhoneBook -> PhoneBook
delEntry = undefined
-- Implementieren Sie eine Funktion `findInMult`, welche alle Einträge aus einer
-- Liste von `PhoneBook`s sucht
findInMult :: [PhoneBook] -> Name -> Entry
findInMult = undefined
result = "Wie war noch mal die Nummer von diesem Alonzo Church? Vielleicht kann der mir weiterhelfen.. \n"
++ (show $ findInMult [pb2,pb3] "Alonzo Church") ++ "\n"
where pb1 = addEntry "Alonzo Church" "(0123) 73645362" mempty
pb2 = delEntry "Alonzo Church" pb1
pb3 = addEntry "Haskell Brooks Curry" "(0167) 987761262" (mappend pb1 pb2)

72
src/Aufgabe1.lhs Normal file
View File

@ -0,0 +1,72 @@
Aufgabe 1
=========
> module Aufgabe1 where
Functional phone book Implementieren Sie ein Telefonbuch als Funktion.
> type Number = String
> type Name = String
> type Entry = [Number]
> newtype PhoneBook = PB (Name -> Entry)
Implementieren Sie die Funktion `usePB`, welche aus einem `PhoneBook`
mit einem `Name` den zugehörigen `Entry` findet`
> usePB :: PhoneBook -> Name -> Entry
> usePB = undefined
Implementieren Sie eine `Monoid` Instanz für `PhoneBook`, um zu garantieren,
dass `PhoneBook` ein leeres Element hat und eine Verkettungsfunktion, die
zwei `PhoneBook`s in eines zusammenführt.
> instance Monoid PhoneBook where
> mempty = undefined
> mappend = undefined
Implementieren Sie eine Funktion `addEntry`, welche einem `PhoneBook` eine
`Name` zu `Number` Verknüpfung hinzufügt, also für einen gegebenen Namen und
eine Nummer einen Eintrag im Telefonbuch erstellt.
> addEntry :: Name -> Number -> PhoneBook -> PhoneBook
> addEntry = undefined
Implementieren Sie eine Funktion `delEntry`, die alle Nummern aus dem `PhoneBook`
entfernt, die mit dem gegebenen `Name` assoziiert sind.
Hinweis: "Entfernt" heißt streng genommen nur, dass die Nummern nicht mehr aus
dem resultierenden Telefonbuch herausgesucht werden können
> delEntry :: Name -> PhoneBook -> PhoneBook
> delEntry = undefined
Implementieren Sie eine Funktion `findInMult`, welche alle Einträge aus einer
Liste von `PhoneBook`s sucht
> findInMult :: [PhoneBook] -> Name -> Entry
> findInMult = undefined
> result = "Wie war noch mal die Nummer von diesem Alonzo Church? Vielleicht kann der mir weiterhelfen.. \n"
> ++ (show $ findInMult [pb2,pb3] "Alonzo Church") ++ "\n"
> where pb1 = addEntry "Alonzo Church" "(0123) 73645362" mempty
> pb2 = delEntry "Alonzo Church" pb1
> pb3 = addEntry "Haskell Brooks Curry" "(0167) 987761262" (mappend pb1 pb2)

79
src/Aufgabe1.md Normal file
View File

@ -0,0 +1,79 @@
Aufgabe 1
=========
```haskell
module Aufgabe1 where
```
Functional phone book Implementieren Sie ein Telefonbuch als Funktion.
```haskell
type Number = String
type Name = String
type Entry = [Number]
newtype PhoneBook = PB (Name -> Entry)
```
Implementieren Sie die Funktion `usePB`, welche aus einem `PhoneBook`
mit einem `Name` den zugehörigen `Entry` findet`
```haskell
usePB :: PhoneBook -> Name -> Entry
usePB = undefined
```
Implementieren Sie eine `Monoid` Instanz für `PhoneBook`, um zu garantieren,
dass `PhoneBook` ein leeres Element hat und eine Verkettungsfunktion, die
zwei `PhoneBook`s in eines zusammenführt.
```haskell
instance Monoid PhoneBook where
mempty = undefined
mappend pb1 pb2 = undefined
```
Implementieren Sie eine Funktion `addEntry`, welche einem `PhoneBook` eine
`Name` zu `Number` Verknüpfung hinzufügt, also für einen gegebenen Namen und
eine Nummer einen Eintrag im Telefonbuch erstellt.
```haskell
addEntry :: Name -> Number -> PhoneBook -> PhoneBook
addEntry n nr pb = undefined
```
Implementieren Sie eine Funktion `delEntry`, die alle Nummern aus dem `PhoneBook`
entfernt, die mit dem gegebenen `Name` assoziiert sind.
Hinweis: "Entfernt" heißt streng genommen nur, dass die Nummern nicht mehr aus
dem resultierenden Telefonbuch herausgesucht werden können
```haskell
delEntry :: Name -> PhoneBook -> PhoneBook
delEntry n pb = undefined
```
Implementieren Sie eine Funktion `findInMult`, welche alle Einträge aus einer
Liste von `PhoneBook`s sucht
```haskell
findInMult :: [PhoneBook] -> Name -> Entry
findInMult = undefined
```
```haskell
result = "Wie war noch mal die Nummer von diesem Alonzo Church? Vielleicht kann der mir weiterhelfen.. \n"
++ (show $ findInMult [pb2,pb3] "Alonzo Church") ++ "\n"
where pb1 = addEntry "Alonzo Church" "(0123) 73645362" mempty
pb2 = delEntry "Alonzo Church" pb1
pb3 = addEntry "Haskell Brooks Curry" "(0167) 987761262" (mappend pb1 pb2)
```

41
src/Aufgabe2.hs Normal file
View File

@ -0,0 +1,41 @@
-- Aufgabe 2
-- =========
module Aufgabe2 where
-- Besser und allgemeiner
-- ----------------------
-- Vereinfachen und verallgemeinern sie folgenden Ausdrücke so weit wie
-- möglich. Geben Sie die dadurch entstehenden Typsignaturen und
-- Funktionsdefinitionen 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 (++[])
mystery2 :: (Int -> Bool)
-> Maybe (Either String Int)
-> Maybe (Either String Bool)
mystery2 f (Just (Right a)) = Just . Right . f $ a
mystery2 _ (Just (Left b)) = Just (Left b)
mystery2 _ Nothing = Nothing
mystery3 :: (Eq a) => a -> a -> a -> Bool
mystery3 x y z
| y == z = True
| z == y && y == x = True
| x /= z = False
| y /= x = False
| z /= y || y /= x = True
| otherwise = False
result = "foo?"

45
src/Aufgabe2.lhs Normal file
View File

@ -0,0 +1,45 @@
Aufgabe 2
=========
> module Aufgabe2 where
Besser und allgemeiner
----------------------
Vereinfachen und verallgemeinern sie folgenden Ausdrücke so weit wie
möglich. Geben Sie die dadurch entstehenden Typsignaturen und
Funktionsdefinitionen 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 (++[])
> mystery2 :: (Int -> Bool)
> -> Maybe (Either String Int)
> -> Maybe (Either String Bool)
> mystery2 f (Just (Right a)) = Just . Right . f $ a
> mystery2 _ (Just (Left b)) = Just (Left b)
> mystery2 _ Nothing = Nothing
> mystery3 :: (Eq a) => a -> a -> a -> Bool
> mystery3 x y z
> | y == z = True
> | z == y && y == x = True
> | x /= z = False
> | y /= x = False
> | z /= y || y /= x = True
> | otherwise = False
> result = "foo?"

47
src/Aufgabe2.md Normal file
View File

@ -0,0 +1,47 @@
Aufgabe 2
=========
```haskell
module Aufgabe2 where
```
Besser und allgemeiner
----------------------
Vereinfachen und verallgemeinern sie folgenden Ausdrücke so weit wie
möglich. Geben Sie die dadurch entstehenden Typsignaturen und
Funktionsdefinitionen 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?
```haskell
mystery1 :: [[a]] -> [[a]]
mystery1 = map (++[])
mystery2 :: (Int -> Bool)
-> Maybe (Either String Int)
-> Maybe (Either String Bool)
mystery2 f (Just (Right a)) = Just . Right . f $ a
mystery2 _ (Just (Left b)) = Just (Left b)
mystery2 _ Nothing = Nothing
mystery3 :: (Eq a) => a -> a -> a -> Bool
mystery3 x y z
| y == z = True
| z == y && y == x = True
| x /= z = False
| y /= x = False
| z /= y || y /= x = True
| otherwise = False
result = "foo?"
```

147
src/Aufgabe3.hs Normal file
View File

@ -0,0 +1,147 @@
-- Aufgabe 3
-- =========
module Aufgabe3 where
import FunPB
import DataPB
import AreaCode
import Data.Char
-- Functor ein Container?
-- --------------------------
-- Zur Erinnerung:
-- class Functor f where
-- fmap :: (a -> b) -> f a -> f b
-- Aus der Vorlesung 2 kennen Sie bereits die `Functor`-Instanzen für `[]`, `Identity`
-- und einen binären Baum. Außerdem haben Sie gelernt, dass Sie auch für Ihre eigenen
-- Typen `Functor`-Instanzen definieren können. Eine Intuition dafür, ob sich für einen
-- Typ eine `Functor`-Instanz schreiben lässt, erhalten Sie, indem Sie sich fragen, ob
-- der Typ "eine Art Container" ist, auf deren Inhalte sich Funktionen (a -> b) anwenden
-- lassen. Was bedeutet dies in Haskell-Syntax? Hierfür ist es dienlich, sich den
-- `type constructor` des betreffenden Datentyps anzuschauen. Handelt es sich um einen
-- polymorphen Datentyp stehen die Chancen gut, dass es ein `Functor` ist.
-- data Bool = False | True
-- data Maybe a = Nothing | Just a
-- data (,) a b = (a,b)
-- `Bool` ist offenbar kein `Functor`, denn der Typkonstruktor `Bool` hat keine Parameter
-- hier ist nur Platz für True und False. `Maybe a` dagegen hat einen Parameter, einen freien
-- Slot für alles mögliche. Der Tupeltyp `(,) a b` hat sogar zwei Parameter er kann Dinge von
-- zwei verschiedenen Typen enthalten. Hier stellt sich die Frage, für welchen Container die
-- Functorinstanz definiert ist. Ähnlich wie Funktionen, lassen sich auch Typkonstruktoren
-- partiell anwenden. Für die Instanziierung werden dem Typkonstruktor daher alle bis auf ein
-- Parameter übergeben. Dieser letzte, freie Parameter legt dann den Inhalt des "Container"
-- fest. Beispiel:
-- instance Functor ((,) a) where --Die Functor-Instanz ist für (,) a definiert
-- fmap f (x,y) = (x, f y) --Also wird über Tupelslot 2 "gemapt"
-- Implementieren Sie `Functor`-Instanzen für die folgenden Datentypen:
data Vielleicht a = Nichts | Etwas a
deriving (Show,Eq)
instance Functor Vielleicht where
fmap = undefined
data Entweder a b = Jenes a | Dieses b
deriving (Show,Eq)
instance Functor (Entweder a) where
fmap = undefined
data Konstant a b = Konstant a
deriving (Show,Eq)
instance Functor (Konstant a) where
fmap = undefined
-- Achtung: Die "Container"-Metapher hat ihre Grenzen. Betrachten Sie hierzu noch einmal den
-- Datentyp Pred a von Zettel 1: `data Pred a = Pred (\a -> Bool)`.
data Pred a = Pred (a -> Bool)
runPred :: Pred a -> (a -> Bool)
runPred (Pred p) = p
-- `Pred a` macht den Anschein als handele es sich auch hier um einen Container mit Inhalt a.
-- Trotzdem lässt sich `Functor` hierfür nicht instanziieren. Der Unterschied liegt darin,
-- dass der Typaramter `a` als Input und nicht als Ergebnis in der vom Konstruktor `Pred`
-- "eingepackten" Berechnung auftaucht. Allerdings lässt sich hier auf eine sehr ähnliche
-- Eigenschaft abstrahieren, die wir für's Erste `InputFunctor` nennen wollen.
class InputFunctor f where
inputmap :: (a -> b) -> f b -> f a
-- Schreiben Sie eine `InputFunctor`-Instanz für `Pred a`.
instance InputFunctor Pred where
inputmap = undefined
-- Hiermit lässt sich nun bequem die folgende Funktion definieren, welche aus einem
-- `Pred Int` ein `Pred String` macht, das prüft, ob ein Eingabestring wenigstens die Länge 5 hat.
atLeast5 :: Pred Int
atLeast5 = Pred $ (\x -> x>=5)
atLeast5Char :: Pred String
atLeast5Char = inputmap length atLeast5
-- Functorial phone book
-- ---------------------
-- Jetzt noch einmal zurück zu PhoneBook aus Aufgabe 1.
type Number = String
type Name = String
type Entry = [Number]
newtype PhoneBook = PB (Name -> Entry)
-- `PhoneBook` hat keinen Parameter, aber die allgemeinere Version `FunPB` hat sogar zwei:
-- data FunPB a b = FunPB (a -> (a,[b]))
-- Beachten Sie, dass sich auch der Rückgabetyp ein wenig unterscheidet. Die Idee ist,
-- dass FunPB zusätzlich zu den assoziierten `Number`s (angenommen `b` ist `Number`) auch
-- den gesuchten `Name` (angenommen `a` ist `Name`) zurückgibt.
-- Implementieren Sie eine `Functor`-Instanz für `FunPB`.
-- Hinweis: Sie können benutzen, dass für `[]`, `((,) a)` und sogar für den "function arrow"
-- `((->) a)` bereits `Functor`-Instanzen in der [`GHC.Base`](https://hackage.haskell.org/package/base "GHC.Base") existieren.
instance Functor (FunPB a) where
fmap = undefined
-- Die Functor-Instanz erlaubt uns nun die Funktionen
-- `separateAreaCode :: Number -> (AreaCode,Number)` und `snd` zu verwenden, um ein
-- TelefonBuch mit separiertem bzw. ganz ohne AreaCode zu erhalten.
areaCodeFunPB :: FunPB Name String -> FunPB Name (AreaCode,Number)
areaCodeFunPB = fmap separateAreaCode
withoutAreaCodeFunPB :: FunPB Name Number -> FunPB Name Number
withoutAreaCodeFunPB = fmap (snd.separateAreaCode)
result = "Suche \"Paula\" in (FunPB Name Number): \n"
++ (show $ runFunPB (dataToFunPB simpleData) "Paula") ++ "\n"
++ "Suche \"Paula\" in (FunPB Name (AreaCode,Number)): \n"
++ (show $ runFunPB (areaCodeFunPB $ dataToFunPB simpleData) "Paula") ++ "\n"
++ "Suche \"Paula\" in (FunPB Name Number) ohne Vorwahl: \n"
++ (show $ runFunPB (withoutAreaCodeFunPB $ dataToFunPB simpleData) "Paula")

168
src/Aufgabe3.lhs Normal file
View File

@ -0,0 +1,168 @@
Aufgabe 3
=========
> module Aufgabe3 where
> import FunPB
> import DataPB
> import AreaCode
> import Data.Char
`Functor` ein Container?
--------------------------
Zur Erinnerung:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Aus der Vorlesung 2 kennen Sie bereits die `Functor`-Instanzen für `[]`, `Identity`
und einen binären Baum. Außerdem haben Sie gelernt, dass Sie auch für Ihre eigenen
Typen `Functor`-Instanzen definieren können. Eine Intuition dafür, ob sich für einen
Typ eine `Functor`-Instanz schreiben lässt, erhalten Sie, indem Sie sich fragen, ob
der Typ "eine Art Container" ist, auf deren Inhalte sich Funktionen (a -> b) anwenden
lassen. Was bedeutet dies in Haskell-Syntax? Hierfür ist es dienlich, sich den
`type constructor` des betreffenden Datentyps anzuschauen. Handelt es sich um einen
polymorphen Datentyp stehen die Chancen gut, dass es ein `Functor` ist.
data Bool = False | True
data Maybe a = Nothing | Just a
data (,) a b = (a,b)
`Bool` ist offenbar kein `Functor`, denn der Typkonstruktor `Bool` hat keine Parameter
hier ist nur Platz für True und False. `Maybe a` dagegen hat einen Parameter, einen freien
Slot für alles mögliche. Der Tupeltyp `(,) a b` hat sogar zwei Parameter er kann Dinge von
zwei verschiedenen Typen enthalten. Hier stellt sich die Frage, für welchen Container die
Functorinstanz definiert ist. Ähnlich wie Funktionen, lassen sich auch Typkonstruktoren
partiell anwenden. Für die Instanziierung werden dem Typkonstruktor daher alle bis auf ein
Parameter übergeben. Dieser letzte, freie Parameter legt dann den Inhalt des "Container"
fest. Beispiel:
instance Functor ((,) a) where --Die Functor-Instanz ist für (,) a definiert
fmap f (x,y) = (x, f y) --Also wird über Tupelslot 2 "gemapt"
Implementieren Sie `Functor`-Instanzen für die folgenden Datentypen:
> data Vielleicht a = Nichts | Etwas a
> deriving (Show,Eq)
> instance Functor Vielleicht where
> fmap = undefined
> data Entweder a b = Jenes a | Dieses b
> deriving (Show,Eq)
> instance Functor (Entweder a) where
> fmap = undefined
> data Konstant a b = Konstant a
> deriving (Show,Eq)
> instance Functor (Konstant a) where
> fmap = undefined
Achtung: Die "Container"-Metapher hat ihre Grenzen. Betrachten Sie hierzu noch einmal den
Datentyp Pred a von Zettel 1: `data Pred a = Pred (\a -> Bool)`.
> data Pred a = Pred (a -> Bool)
> runPred :: Pred a -> (a -> Bool)
> runPred (Pred p) = p
`Pred a` macht den Anschein als handele es sich auch hier um einen Container mit Inhalt a.
Trotzdem lässt sich `Functor` hierfür nicht instanziieren. Der Unterschied liegt darin,
dass der Typaramter `a` als Input und nicht als Ergebnis in der vom Konstruktor `Pred`
"eingepackten" Berechnung auftaucht. Allerdings lässt sich hier auf eine sehr ähnliche
Eigenschaft abstrahieren, die wir für's Erste `InputFunctor` nennen wollen.
```
> class InputFunctor f where
> inputmap :: (a -> b) -> f b -> f a
Schreiben Sie eine `InputFunctor`-Instanz für `Pred a`.
> instance InputFunctor Pred where
> inputmap = undefined
Hiermit lässt sich nun bequem die folgende Funktion definieren, welche aus einem
`Pred Int` ein `Pred String` macht, das prüft, ob ein Eingabestring wenigstens die Länge 5 hat.
> atLeast5 :: Pred Int
> atLeast5 = Pred $ (\x -> x>=5)
> atLeast5Char :: Pred String
> atLeast5Char = inputmap length atLeast5
Functorial phone book
---------------------
Jetzt noch einmal zurück zu PhoneBook aus Aufgabe 1.
> type Number = String
> type Name = String
> type Entry = [Number]
> newtype PhoneBook = PB (Name -> Entry)
`PhoneBook` hat keinen Parameter, aber die allgemeinere Version `FunPB` hat sogar zwei:
data FunPB a b = FunPB (a -> (a,[b]))
Beachten Sie, dass sich auch der Rückgabetyp ein wenig unterscheidet. Die Idee ist,
dass FunPB zusätzlich zu den assoziierten `Number`s (angenommen `b` ist `Number`) auch
den gesuchten `Name` (angenommen `a` ist `Name`) zurückgibt.
Implementieren Sie eine `Functor`-Instanz für `FunPB`.
Hinweis: Sie können benutzen, dass für `[]`, `((,) a)` und sogar für den "function arrow"
`((->) a)` bereits `Functor`-Instanzen in der [`GHC.Base`](https://hackage.haskell.org/package/base "GHC.Base") existieren.
> instance Functor (FunPB a) where
> fmap = undefined
Die Functor-Instanz erlaubt uns nun die Funktionen
`separateAreaCode :: Number -> (AreaCode,Number)` und `snd` zu verwenden, um ein
TelefonBuch mit separiertem bzw. ganz ohne AreaCode zu erhalten.
> areaCodeFunPB :: FunPB Name String -> FunPB Name (AreaCode,Number)
> areaCodeFunPB = fmap separateAreaCode
> withoutAreaCodeFunPB :: FunPB Name Number -> FunPB Name Number
> withoutAreaCodeFunPB = fmap (snd.separateAreaCode)
> result = "Suche \"Paula\" in (FunPB Name Number): \n"
> ++ (show $ runFunPB (dataToFunPB simpleData) "Paula") ++ "\n"
> ++ "Suche \"Paula\" in (FunPB Name (AreaCode,Number)): \n"
> ++ (show $ runFunPB (areaCodeFunPB $ dataToFunPB simpleData) "Paula") ++ "\n"
> ++ "Suche \"Paula\" in (FunPB Name Number) ohne Vorwahl: \n"
> ++ (show $ runFunPB (withoutAreaCodeFunPB $ dataToFunPB simpleData) "Paula")

171
src/Aufgabe3.md Normal file
View File

@ -0,0 +1,171 @@
Aufgabe 3
=========
```haskell
module Aufgabe3 where
import FunPB
import DataPB
import AreaCode
import Data.Char
```
`Functor` ein Container?
--------------------------
Zur Erinnerung:
```haskell
class Functor f where
fmap :: (a -> b) -> f a -> f b
```
Aus der Vorlesung 2 kennen Sie bereits die `Functor`-Instanzen für `[]`, `Identity`
und einen binären Baum. Außerdem haben Sie gelernt, dass Sie auch für Ihre eigenen
Typen `Functor`-Instanzen definieren können. Eine Intuition dafür, ob sich für einen
Typ eine `Functor`-Instanz schreiben lässt, erhalten Sie, indem Sie sich fragen, ob
der Typ "eine Art Container" ist, auf deren Inhalte sich Funktionen (a -> b) anwenden
lassen. Was bedeutet dies in Haskell-Syntax? Hierfür ist es dienlich, sich den
`type constructor` des betreffenden Datentyps anzuschauen. Handelt es sich um einen
polymorphen Datentyp stehen die Chancen gut, dass es ein `Functor` ist.
```haskell
data Bool = False | True
data Maybe a = Nothing | Just a
data (,) a b = (a,b)
```
`Bool` ist offenbar kein `Functor`, denn der Typkonstruktor `Bool` hat keine Parameter
hier ist nur Platz für True und False. `Maybe a` dagegen hat einen Parameter, einen freien
Slot für alles mögliche. Der Tupeltyp `(,) a b` hat sogar zwei Parameter er kann Dinge von
zwei verschiedenen Typen enthalten. Hier stellt sich die Frage, für welchen Container die
Functorinstanz definiert ist. Ähnlich wie Funktionen, lassen sich auch Typkonstruktoren
partiell anwenden. Für die Instanziierung werden dem Typkonstruktor daher alle bis auf ein
Parameter übergeben. Dieser letzte, freie Parameter legt dann den Inhalt des "Container"
fest. Beispiel:
```haskell
instance Functor ((,) a) where --Die Functor-Instanz ist für (,) a definiert
fmap f (x,y) = (x, f y) --Also wird über Tupelslot 2 "gemapt"
```
Implementieren Sie `Functor`-Instanzen für die folgenden Datentypen:
```haskell
data Vielleicht a = Nichts | Etwas a
deriving (Show,Eq)
instance Functor Vielleicht where
fmap = undefined
data Entweder a b = Jenes a | Dieses b
deriving (Show,Eq)
instance Functor (Entweder a) where
fmap = undefined
data Konstant a b = Konstant a
deriving (Show,Eq)
instance Functor (Konstant a) where
fmap = undefined
```
Achtung: Die "Container"-Metapher hat ihre Grenzen. Betrachten Sie hierzu noch einmal den
Datentyp Pred a von Zettel 1: `data Pred a = Pred (\a -> Bool)`.
```haskell
data Pred a = Pred (a -> Bool)
runPred :: Pred a -> (a -> Bool)
runPred (Pred p) = p
```
`Pred a` macht den Anschein als handele es sich auch hier um einen Container mit Inhalt a.
Trotzdem lässt sich `Functor` hierfür nicht instanziieren. Der Unterschied liegt darin,
dass der Typaramter `a` als Input und nicht als Ergebnis in der vom Konstruktor `Pred`
"eingepackten" Berechnung auftaucht. Allerdings lässt sich hier auf eine sehr ähnliche
Eigenschaft abstrahieren, die wir für's Erste `InputFunctor` nennen wollen.
```haskell
class InputFunctor f where
inputmap :: (a -> b) -> f b -> f a
```
Schreiben Sie eine `InputFunctor`-Instanz für `Pred a`.
```haskell
instance InputFunctor Pred where
inputmap = undefined
```
Hiermit lässt sich nun bequem die folgende Funktion definieren, welche aus einem
`Pred Int` ein `Pred String` macht, das prüft, ob ein Eingabestring wenigstens die Länge 5 hat.
```haskell
atLeast5 :: Pred Int
atLeast5 = Pred $ (\x -> x>=5)
atLeast5Char :: Pred String
atLeast5Char = inputmap length atLeast5
```
Functorial phone book
---------------------
Jetzt noch einmal zurück zu PhoneBook aus Aufgabe 1.
```haskell
type Number = String
type Name = String
type Entry = [Number]
newtype PhoneBook = PB (Name -> Entry)
```
`PhoneBook` hat keinen Parameter, aber die allgemeinere Version `FunPB` hat sogar zwei:
```haskell
data FunPB a b = FunPB (a -> (a,[b]))
```
Beachten Sie, dass sich auch der Rückgabetyp ein wenig unterscheidet. Die Idee ist,
dass FunPB zusätzlich zu den assoziierten `Number`s (angenommen `b` ist `Number`) auch
den gesuchten `Name` (angenommen `a` ist `Name`) zurückgibt.
Implementieren Sie eine `Functor`-Instanz für `FunPB`.
Hinweis: Sie können benutzen, dass für `[]`, `((,) a)` und sogar für den "function arrow"
`((->) a)` bereits `Functor`-Instanzen in der [`GHC.Base`](https://hackage.haskell.org/package/base "GHC.Base") existieren.
```haskell
instance Functor (FunPB a) where
fmap = undefined
```
Die Functor-Instanz erlaubt uns nun die Funktionen
`separateAreaCode :: Number -> (AreaCode,Number)` und `snd` zu verwenden, um ein
TelefonBuch mit separiertem bzw. ganz ohne AreaCode zu erhalten.
```haskell
areaCodeFunPB :: FunPB Name Number -> FunPB Name (AreaCode,Number)
areaCodeFunPB = fmap separateAreaCode
withoutAreaCodeFunPB :: FunPB Name Number -> FunPB Name Number
withoutAreaCodeFunPB = fmap (snd.separateAreaCode)
```
```haskell
result = "Suche \"Paula\" in (FunPB Name Number): \n"
++ (show $ runFunPB (dataToFunPB simpleData) "Paula") ++ "\n"
++ "Suche \"Paula\" in (FunPB Name (AreaCode,Number)): \n"
++ (show $ runFunPB (areaCodeFunPB $ dataToFunPB simpleData) "Paula") ++ "\n"
++ "Suche \"Paula\" in (FunPB Name Number) ohne Vorwahl: \n"
++ (show $ runFunPB (withoutAreaCodeFunPB $ dataToFunPB simpleData) "Paula")
```

View File

@ -1,85 +1,6 @@
-- Aufgabe 4
-- =========
module Aufgabe4 where
-- Aufgabe 4 finden befindet sich auf dem Branch `ghc-vis`.
-- Weitere Informationen in der README.md
-- Ein paar Infos
-- --------------
-- In der Vorlesung haben Sie schon kennengelernt, dass Haskell 'Lazy' ist. In
-- dieser Übung werden Sie dies graphisch erfahren können.
-- Hinweis:
-- Da wir direkt auf den Evaluationstatus von einzelnen Ausdrücken zugreifen
-- wollen, und sich der compilierte ByteCode von unterschiedlichen GHC Versionen
-- sehr unterschiedlich ist, arbeiten wir für diese Übung mit GHC < 8.*
-- Zur Visualisierung der Ausdrücke nutzen wir ghc-vis. Dies integriert sich
-- dank eines Scripts direkt in den GHCi.
-- Befehle:
-- :vis Öffnet das ghc-vis Fenster (haben Sie dies geschlossen müssen Sie
-- vermutlich den GHCi nocheinmal starten bevor Sie ghc-vis erneut öffnen
-- können
-- :view x Zeigt den Ausdruck "x" grafisch an
-- :switch Schaltet den Anzeigemodus um
-- :clear Säubert die Anzeige
-- Aufgabenstellung
-- ----------------
ones = [1,1..]
list = [1,3..]
list' = [1,5..]
-- Starten Sie nun ghc-vis mit dem Befehl ":vis" und lassen sich zunächst `ones`
-- anzeigen ":view ones"
-- Sie können einfach auf einen Eintrag klicken um diesen evaluieren zu lassen
-- (dafür darf der Eintrag noch nicht vollständig evaluiert sein).
-- Dies können Sie nun auch mit den anderen Listen machen.
-- (1) Erstellen Sie eine PDF (ghc-vis > File > Export) in der die Listen bis
-- mindestens zu ihrem 10ten Element ausgewertet sind. Fassen Sie zusätzlich in
-- Stichpunkten die Unterschiede der Listen zusammen.
-- Lassen Sie sich nun auf die gleiche Art eine unendliche Liste aller Fibonacci
-- Zahlen anzeigen.
f = 0:1:zipWith (+) f (tail f)
-- :clear
-- :view f
-- (2) Interpretieren Sie das nun sichtbare in kurzen Stichpunkten. Erstellen Sie nun
-- eine PDF in der die ersten 10 Fibonacci Zahlen UNAUSGEWERTET (also als Thunks)
-- vorliegen. Nun sollte es für Sie möglich sein, mit einem Klick alle noch nicht
-- berechneten Fibonacci Zahlen berechnen zu lassen. Speichern Sie auch diesen
-- Graph als PDF.
primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p > 0]
-- Lassen sie sich `primes` im ghc-vis anzeigen. Dies stellt eine unendliche Liste
-- von Primzahlen dar, die durch das "Sieb des Eratosthenes" erzeugt werden.
-- Das Prinzip dieses Siebes ist es, Primzahlen zu finden, indem jede Zahl mit
-- 2 beginnend `[2..]` durch alle bereits gefundenden Primzahlen geteilt wird, um
-- zu prüfen, ob eine unteilbare Zahl, und damit eine Primzahl, vorliegt.
-- (3) Erstellen Sie eine PDF, in der noch nicht gefilterte/überprüfte Zahlen
-- (5-10) zu erkennen sind, sowie bereits als Primzahl erkannte Zahlen UND Zahlen, die
-- bereits teilweise gefiltert sind.
result = "No need to write code for this exercise!"
result = "foo"

View File

@ -1,85 +1,6 @@
Aufgabe 4
=========
> module Aufgabe4 where
Aufgabe 4 finden befindet sich auf dem Branch `ghc-vis`.
Weitere Informationen in der README.md
Ein paar Infos
--------------
In der Vorlesung haben Sie schon kennengelernt, dass Haskell 'Lazy' ist. In
dieser Übung werden Sie dies graphisch erfahren können.
Hinweis:
Da wir direkt auf den Evaluationstatus von einzelnen Ausdrücken zugreifen
wollen, und sich der compilierte ByteCode von unterschiedlichen GHC Versionen
sehr unterschiedlich ist, arbeiten wir für diese Übung mit GHC < 8.*
Zur Visualisierung der Ausdrücke nutzen wir ghc-vis. Dies integriert sich
dank eines Scripts direkt in den GHCi.
Befehle:
:vis Öffnet das ghc-vis Fenster (haben Sie dies geschlossen müssen Sie
vermutlich den GHCi nocheinmal starten bevor Sie ghc-vis erneut öffnen
können
:view x Zeigt den Ausdruck "x" grafisch an
:switch Schaltet den Anzeigemodus um
:clear Säubert die Anzeige
Aufgabenstellung
----------------
> ones = [1,1..]
>
> list = [1,3..]
>
> list' = [1,5..]
Starten Sie nun ghc-vis mit dem Befehl ":vis" und lassen sich zunächst `ones`
anzeigen ":view ones"
Sie können einfach auf einen Eintrag klicken um diesen evaluieren zu lassen
(dafür darf der Eintrag noch nicht vollständig evaluiert sein).
Dies können Sie nun auch mit den anderen Listen machen.
(1) Erstellen Sie eine PDF (ghc-vis > File > Export) in der die Listen bis
mindestens zu ihrem 10ten Element ausgewertet sind. Fassen Sie zusätzlich in
Stichpunkten die Unterschiede der Listen zusammen.
Lassen Sie sich nun auf die gleiche Art eine unendliche Liste aller Fibonacci
Zahlen anzeigen.
> f = 0:1:zipWith (+) f (tail f)
:clear
:view f
(2) Interpretieren Sie das nun sichtbare in kurzen Stichpunkten. Erstellen Sie nun
eine PDF in der die ersten 10 Fibonacci Zahlen UNAUSGEWERTET (also als Thunks)
vorliegen. Nun sollte es für Sie möglich sein, mit einem Klick alle noch nicht
berechneten Fibonacci Zahlen berechnen zu lassen. Speichern Sie auch diesen
Graph als PDF.
> primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p > 0]
Lassen sie sich `primes` im ghc-vis anzeigen. Dies stellt eine unendliche Liste
von Primzahlen dar, die durch das "Sieb des Eratosthenes" erzeugt werden.
Das Prinzip dieses Siebes ist es, Primzahlen zu finden, indem jede Zahl mit
2 beginnend `[2..]` durch alle bereits gefundenden Primzahlen geteilt wird, um
zu prüfen, ob eine unteilbare Zahl, und damit eine Primzahl, vorliegt.
(3) Erstellen Sie eine PDF, in der noch nicht gefilterte/überprüfte Zahlen
(5-10) zu erkennen sind, sowie bereits als Primzahl erkannte Zahlen UND Zahlen, die
bereits teilweise gefiltert sind.
> result = "No need to write code for this exercise!"
> result = "foo"

View File

@ -1,85 +1,6 @@
Aufgabe 4
=========
> module Aufgabe4 where
Aufgabe 4 finden befindet sich auf dem Branch `ghc-vis`.
Weitere Informationen in der README.md
Ein paar Infos
--------------
In der Vorlesung haben Sie schon kennengelernt, dass Haskell 'Lazy' ist. In
dieser Übung werden Sie dies graphisch erfahren können.
Hinweis:
Da wir direkt auf den Evaluationstatus von einzelnen Ausdrücken zugreifen
wollen, und sich der compilierte ByteCode von unterschiedlichen GHC Versionen
sehr unterschiedlich ist, arbeiten wir für diese Übung mit GHC < 8.*
Zur Visualisierung der Ausdrücke nutzen wir ghc-vis. Dies integriert sich
dank eines Scripts direkt in den GHCi.
Befehle:
:vis Öffnet das ghc-vis Fenster (haben Sie dies geschlossen müssen Sie
vermutlich den GHCi nocheinmal starten bevor Sie ghc-vis erneut öffnen
können
:view x Zeigt den Ausdruck "x" grafisch an
:switch Schaltet den Anzeigemodus um
:clear Säubert die Anzeige
Aufgabenstellung
----------------
> ones = [1,1..]
>
> list = [1,3..]
>
> list' = [1,5..]
Starten Sie nun ghc-vis mit dem Befehl ":vis" und lassen sich zunächst `ones`
anzeigen ":view ones"
Sie können einfach auf einen Eintrag klicken um diesen evaluieren zu lassen
(dafür darf der Eintrag noch nicht vollständig evaluiert sein).
Dies können Sie nun auch mit den anderen Listen machen.
(1) Erstellen Sie eine PDF (ghc-vis > File > Export) in der die Listen bis
mindestens zu ihrem 10ten Element ausgewertet sind. Fassen Sie zusätzlich in
Stichpunkten die Unterschiede der Listen zusammen.
Lassen Sie sich nun auf die gleiche Art eine unendliche Liste aller Fibonacci
Zahlen anzeigen.
> f = 0:1:zipWith (+) f (tail f)
:clear
:view f
(2) Interpretieren Sie das nun sichtbare in kurzen Stichpunkten. Erstellen Sie nun
eine PDF in der die ersten 10 Fibonacci Zahlen UNAUSGEWERTET (also als Thunks)
vorliegen. Nun sollte es für Sie möglich sein, mit einem Klick alle noch nicht
berechneten Fibonacci Zahlen berechnen zu lassen. Speichern Sie auch diesen
Graph als PDF.
> primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p > 0]
Lassen sie sich `primes` im ghc-vis anzeigen. Dies stellt eine unendliche Liste
von Primzahlen dar, die durch das "Sieb des Eratosthenes" erzeugt werden.
Das Prinzip dieses Siebes ist es, Primzahlen zu finden, indem jede Zahl mit
2 beginnend `[2..]` durch alle bereits gefundenden Primzahlen geteilt wird, um
zu prüfen, ob eine unteilbare Zahl, und damit eine Primzahl, vorliegt.
(3) Erstellen Sie eine PDF, in der noch nicht gefilterte/überprüfte Zahlen
(5-10) zu erkennen sind, sowie bereits als Primzahl erkannte Zahlen UND Zahlen, die
bereits teilweise gefiltert sind.
> result = "No need to write code for this exercise!"
> result = "foo"

9
src/DataPB.hs Normal file
View File

@ -0,0 +1,9 @@
module DataPB where
import qualified Data.Attoparsec.Text as A
import Data.Attoparsec.Combinator
import qualified Data.Text as T
simpleData :: [(String,String)]
simpleData = [("Phillip","(04165) 6048168"),("Michael","(0148) 56121127"),("Phillip","(03548) 4538973"),("Paula","(030) 664940"),("Paul","(088) 08933337"),("Sylvester","(035588) 582174"),("Harriet","(0751) 75825269"),("Ariane","(0302) 49046118"),("Michael","(06650) 6975458"),("Kylie","(046) 77199945"),("Lee","(032509) 210171"),("Hunter","(06929) 7068643"),("Marvin","(036623) 741589"),("Paul","(0229) 13909736"),("Linda","(0859) 15505790"),("Lydia","(039229) 379675"),("Michael","(0755) 98407141"),("Skyler","(035869) 897089"),("Ariane","(035) 22332444"),("Eden","(0080) 20592805"),("John","(09857) 4504229"),("Jenette","(0182) 34362051"),("Delilah","(035690) 139671"),("Michael","(034973) 388559"),("John","(0451) 08133630"),("Madonna","(03897) 0007997"),("Madeline","(0600) 19801141"),("Francesca","(087) 58002539"),("Latifah","(04010) 3533294"),("Lucas","(08963) 4253453"),("Acton","(034060) 453837"),("Shelby","(039459) 871551"),("Keiko","(047) 07336335"),("Moses","(017) 73610349"),("Samantha","(034114) 317044"),("Logan","(00017) 2404967"),("Marcia","(041) 04583123"),("Allistair","(0707) 04978234"),("Hedwig","(037227) 674138"),("Phillip","(01175) 6633514"),("Paul","(084) 47394790"),("Paula","(0243) 06440875"),("Michael","(065) 98178780"),("Paul","(00622) 0087233"),("Stacy","(004) 38785128"),("Stephen","(043) 84694380"),("Michael","(053) 55705629"),("Christine","(001) 44243108"),("Paul","(030513) 239204"),("Phillip","(07043) 5061835"),("Paula","(036638) 3341652")]

21
src/FunPB.hs Normal file
View File

@ -0,0 +1,21 @@
module FunPB where
import Control.Monad
data FunPB a b = FunPB { runFunPB :: a -> (a,[b]) }
instance Monoid (FunPB a b) where
mempty = FunPB $ \k -> (k,mempty)
mappend pb1 pb2 = FunPB $ \n -> (,) n $ msum . (<$>) (uncurry (flip const).((flip runFunPB) n)) $ [pb1,pb2]
addAssoc :: Eq a => (a,b) -> FunPB a b -> FunPB a b
addAssoc (n,nr) pb = FunPB $ \n' -> if n' == n then ((:) nr) <$> runFunPB pb n' else runFunPB pb n'
delAssoc :: Eq a => a -> FunPB a b -> FunPB a b
delAssoc n pb = FunPB $ \n' -> if n == n' then runFunPB mempty n' else runFunPB pb n'
multiFind :: [FunPB a b] -> a -> (a,[b])
multiFind = runFunPB.mconcat
dataToFunPB :: Eq a => [(a,b)] -> FunPB a b
dataToFunPB = mconcat.fmap ((flip addAssoc) mempty)

View File

@ -1,11 +1,5 @@
flags: {}
extra-package-dbs: []
packages:
- '.'
extra-deps:
- ghc-vis-0.8
- svgcairo-0.13.1.1
- xdot-0.3.0.1
- Cabal-1.24.2.0
- gtk2hs-buildtools-0.13.2.2
resolver: lts-6.31
extra-deps: []
resolver: lts-8.9

66
test/Aufgabe1-Spec.hs Normal file
View File

@ -0,0 +1,66 @@
import Aufgabe1
import Test.Framework.Providers.HUnit (testCase)
import Test.Framework.Runners.Console (defaultMain)
import Test.HUnit
{- TEST DATA -}
data1,data2,data3 :: [(String,String)]
data1 = [("Phillip","(04165) 9876543"),("Phillip","(03548) 1234567"),("Paula","(035383) 567890")]
data2 = [("Paula","(04165) 8765432"),("Michael","(03548) 2345678"),("Ariane","(035383) 678901")]
data3 = [("Paula","(04165) 7654321"),("Hannelore","(03548) 3456789"),("Helmut","(035383) 789012")]
noData :: [(String,String)]
noData = mempty
xPB :: PhoneBook
xPB = PB $ \n -> [b|(a,b)<-data1, n==a]
yPB :: PhoneBook
yPB = PB $ \n -> [b|(a,b)<-data2, n==a]
zPB :: PhoneBook
zPB = PB $ \n -> [b|(a,b)<-data3, n==a]
examplePB = xPB
emptyPhoneBook :: PhoneBook
emptyPhoneBook = PB $ \a -> [b|(a,b)<-noData]
{- TEST CASES -}
usePBTest = testCase "Benutze beispielhaftes PhoneBook"
$ assertEqual "usePB examplePB \"Phillip\" sollte folgende zwei Nummern rausgeben" ["(04165) 9876543","(03548) 1234567"]
$ usePB examplePB "Phillip"
mappendTest = testCase "Assoziativität von mappend"
$ assertEqual "Assoziativität von mappend ist nicht erfüllt" (usePB (mappend (mappend xPB yPB) zPB) "Paula")
$ usePB (mappend xPB $ mappend yPB zPB) "Paula"
memptyTest1 = testCase "Linksidentität von mempty"
$ assertEqual "Linksidentität von mempty ist nicht erfüllt" (usePB xPB "Phillip")
$ usePB (mappend xPB mempty) "Phillip"
memptyTest2 = testCase "Rechtsidentität von mempty"
$ assertEqual "Rechtsidentität von mempty ist nicht erfüllt" (usePB xPB "Phillip")
$ usePB (mappend mempty xPB) "Phillip"
addEntryTest = testCase "Füge Name-Nummer-Verknüpfung hinzu"
$ assertEqual "Die hinzugefügte Nummer wird nicht gefunden" ["12345"]
$ usePB (addEntry "NeuerName" "12345" emptyPhoneBook) "NeuerName"
delEntryTest = testCase "Lösche Name-Nummer-Verknüpfung"
$ assertEqual "Die gelöschte Nummer wird weiterhin gefunden" []
$ usePB (delEntry "Paula" xPB) "Paula"
findInMultTest = testCase "Suche in mehreren PhoneBooks"
$ assertEqual "Es werden nicht alle drei Nummern von Paula gefunden" ["(035383) 567890","(04165) 8765432","(04165) 7654321"]
$ findInMult [xPB,yPB,zPB] "Paula"
tests = [usePBTest,mappendTest,memptyTest1,memptyTest2,addEntryTest,delEntryTest,findInMultTest]
main :: IO ()
main = defaultMain tests

7
test/Aufgabe2-Spec.hs Normal file
View File

@ -0,0 +1,7 @@
main :: IO ()
main = putStrLn $ "Eine Testung von Aufgabe 2 mit HUnit ist nicht sinnvoll. \n"
++ "Falls Sie feststecken und nicht weiterkommen: \n"
++ "Welche Typklassen kennen Sie? \n"
++ "Wie sehen deren Instanzen für die vorliegenden Datentypen aus? \n"
++ "Welche Regeln/Gesetze implizieren diese Typklassen? \n"
++ "Eventuell lassen sich Ausdrücke mehrfach verallgemeinern. \n"

77
test/Aufgabe3-Spec.hs Normal file
View File

@ -0,0 +1,77 @@
import Aufgabe3
import DataPB
import FunPB
import AreaCode
import Test.Framework.Providers.HUnit (testCase)
import Test.Framework.Runners.Console (defaultMain)
import Test.HUnit
{- TEST DATA -}
funPBTest = dataToFunPB simpleData
vielleichtValues = [(Etwas 1234),Nichts]
entwederValues :: [Entweder String [[[Integer]]]]
entwederValues = [(Jenes "just a string"),(Dieses [[[12344321]]])]
konstantValue = Konstant True
f = const 1
g = const '0'
{- TEST CASES-}
atleast5CharFalse = testCase "Teste Randbedingung (==False) für atleast5Char"
$ assertEqual "Der Ausdruck >>> runPred atLeast5Char $ \"1234\" \nsollte zu False auswerten" False
$ runPred atLeast5Char $ "1234"
atleast5CharTrue = testCase "Teste Randbedingung (==True) für atleast5Char"
$ assertEqual "Der Ausdruck >>> runPred atLeast5Char $ \"12345\" \nsollte zu True auswerten" True
$ runPred atLeast5Char $ "12345"
fmapVielleichtTestIdentity = testCase "Functor Vielleicht: Strukturerhaltung"
$ assertEqual "Es sollte gelten: fmap id == id . " (id <$> vielleichtValues)
$ ((fmap id) <$> vielleichtValues)
fmapVielleichtTestComposability = testCase "Functor Vielleicht: Komponierbarkeit"
$ assertEqual "Es sollte gelten: fmap f . fmap g == fmap (f . g) . " ((fmap f . fmap g) <$> vielleichtValues)
$ ((fmap (f . g)) <$> vielleichtValues)
fmapEntwederTestIdentity = testCase "Functor (Entweder a): Strukturerhaltung"
$ assertEqual "Es sollte gelten: fmap id == id . " (id <$> entwederValues)
$ ((fmap id) <$> entwederValues)
fmapEntwederTestComposability = testCase "Functor (Entweder a): Komponierbarkeit"
$ assertEqual "Es sollte gelten: fmap f . fmap g == fmap (f . g) . " ((fmap f . fmap g) <$> entwederValues)
$ ((fmap (f . g)) <$> entwederValues)
fmapKonstantTestIdentity = testCase "Functor (Konstant a): Strukturerhaltung"
$ assertEqual "Es sollte gelten: fmap id == id . " (id konstantValue)
$ ((fmap id) konstantValue)
fmapKonstantTestComposability = testCase "Functor (Konstant a): Komponierbarkeit"
$ assertEqual "Es sollte gelten: fmap f . fmap g == fmap (f . g) . " ((fmap f . fmap g) konstantValue)
$ ((fmap (f . g)) konstantValue)
fmapFunPBTestIdentity = testCase "Functor (FunPB a): Strukturerhaltung"
$ assertEqual "Es sollte gelten: fmap id == id . " (runFunPB (id funPBTest) "Paula")
$ (runFunPB ((fmap id) funPBTest) "Paula")
fmapFunPBTestComposability = testCase "Functor (FunPB a): Komponierbarkeit"
$ assertEqual "Es sollte gelten: fmap f . fmap g == fmap (f . g) . " (runFunPB (fmap snd . fmap separateAreaCode $ funPBTest) "Paula")
$ (runFunPB ((fmap (snd.separateAreaCode)) funPBTest) "Paula")
tests = [atleast5CharFalse,atleast5CharTrue,fmapVielleichtTestIdentity,fmapVielleichtTestComposability,fmapEntwederTestIdentity,fmapEntwederTestComposability,fmapKonstantTestIdentity,fmapKonstantTestComposability,fmapFunPBTestIdentity,fmapFunPBTestComposability]
main :: IO ()
main = defaultMain tests

View File

@ -18,8 +18,74 @@ cabal-version: >=1.10
-- to solve assignments
library
hs-source-dirs: src
exposed-modules: Aufgabe4
exposed-modules: Lib
, DataPB
, AreaCode
, FunPB
, Aufgabe1
, Aufgabe2
, Aufgabe3
, Aufgabe4
build-depends: base >= 4.7 && < 5
, attoparsec
, text
default-language: Haskell2010
executable aufgabe1
hs-source-dirs: app
main-is: Aufgabe1Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, zettel2
default-language: Haskell2010
test-suite aufgabe1-tests
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Aufgabe1-Spec.hs
build-depends: base
, zettel2
, test-framework
, test-framework-hunit
, HUnit
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010
executable aufgabe2
hs-source-dirs: app
main-is: Aufgabe2Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, zettel2
default-language: Haskell2010
test-suite aufgabe2-tests
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Aufgabe2-Spec.hs
build-depends: base
, zettel2
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010
executable aufgabe3
hs-source-dirs: app
main-is: Aufgabe3Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, zettel2
default-language: Haskell2010
test-suite aufgabe3-tests
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Aufgabe3-Spec.hs
build-depends: base
, zettel2
, test-framework
, test-framework-hunit
, HUnit
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010
executable aufgabe4
@ -28,7 +94,15 @@ executable aufgabe4
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, zettel2
, ghc-vis
default-language: Haskell2010
test-suite aufgabe4-tests
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Aufgabe4-Spec.hs
build-depends: base
, zettel2
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010
source-repository head