diff --git a/.ghci b/.ghci new file mode 100644 index 0000000..6e48b23 --- /dev/null +++ b/.ghci @@ -0,0 +1,29 @@ +: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 + diff --git a/app/Aufgabe1Main.hs b/app/Aufgabe1Main.hs deleted file mode 100644 index a8a86ee..0000000 --- a/app/Aufgabe1Main.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import Aufgabe1 - -main :: IO () -main = putStrLn result diff --git a/app/Aufgabe2Main.hs b/app/Aufgabe2Main.hs deleted file mode 100644 index 19eac74..0000000 --- a/app/Aufgabe2Main.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import Aufgabe2 - -main :: IO () -main = putStrLn result diff --git a/app/Aufgabe3Main.hs b/app/Aufgabe3Main.hs deleted file mode 100644 index 8c9213d..0000000 --- a/app/Aufgabe3Main.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import Aufgabe3 - -main :: IO () -main = putStrLn result diff --git a/install_dependencies.sh b/install_dependencies.sh new file mode 100644 index 0000000..45510ed --- /dev/null +++ b/install_dependencies.sh @@ -0,0 +1,2 @@ +tar xf /media/remote/ygottschalk/.stack.tar.gz -C $HOME/ + diff --git a/src/AreaCode.hs b/src/AreaCode.hs deleted file mode 100644 index 3e72087..0000000 --- a/src/AreaCode.hs +++ /dev/null @@ -1,27 +0,0 @@ -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 - diff --git a/src/Aufgabe1.hs b/src/Aufgabe1.hs deleted file mode 100644 index fa310ea..0000000 --- a/src/Aufgabe1.hs +++ /dev/null @@ -1,82 +0,0 @@ --- 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) - - - - - - - - - - - - - - - - diff --git a/src/Aufgabe1.lhs b/src/Aufgabe1.lhs deleted file mode 100644 index feab504..0000000 --- a/src/Aufgabe1.lhs +++ /dev/null @@ -1,72 +0,0 @@ -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) - - - - diff --git a/src/Aufgabe1.md b/src/Aufgabe1.md deleted file mode 100644 index d6105fe..0000000 --- a/src/Aufgabe1.md +++ /dev/null @@ -1,79 +0,0 @@ -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) -``` - - - - - - - diff --git a/src/Aufgabe2.hs b/src/Aufgabe2.hs deleted file mode 100644 index e0bd4ef..0000000 --- a/src/Aufgabe2.hs +++ /dev/null @@ -1,41 +0,0 @@ --- 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?" - - - diff --git a/src/Aufgabe2.lhs b/src/Aufgabe2.lhs deleted file mode 100644 index b61cafb..0000000 --- a/src/Aufgabe2.lhs +++ /dev/null @@ -1,45 +0,0 @@ -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?" - - - diff --git a/src/Aufgabe2.md b/src/Aufgabe2.md deleted file mode 100644 index 5a1df0b..0000000 --- a/src/Aufgabe2.md +++ /dev/null @@ -1,47 +0,0 @@ -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?" -``` - - diff --git a/src/Aufgabe3.hs b/src/Aufgabe3.hs deleted file mode 100644 index 66f180c..0000000 --- a/src/Aufgabe3.hs +++ /dev/null @@ -1,147 +0,0 @@ --- 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") - - - - - diff --git a/src/Aufgabe3.lhs b/src/Aufgabe3.lhs deleted file mode 100644 index 8274047..0000000 --- a/src/Aufgabe3.lhs +++ /dev/null @@ -1,168 +0,0 @@ -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") - - - - diff --git a/src/Aufgabe3.md b/src/Aufgabe3.md deleted file mode 100644 index 5b43008..0000000 --- a/src/Aufgabe3.md +++ /dev/null @@ -1,171 +0,0 @@ -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") - -``` - diff --git a/src/Aufgabe4.hs b/src/Aufgabe4.hs index ea7a72e..c91a5a4 100644 --- a/src/Aufgabe4.hs +++ b/src/Aufgabe4.hs @@ -1,6 +1,85 @@ +-- Aufgabe 4 +-- ========= + module Aufgabe4 where --- Aufgabe 4 finden befindet sich auf dem Branch `ghc-vis`. --- Weitere Informationen in der README.md -result = "foo" +-- 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!" + diff --git a/src/Aufgabe4.lhs b/src/Aufgabe4.lhs index cbf40b0..7185466 100644 --- a/src/Aufgabe4.lhs +++ b/src/Aufgabe4.lhs @@ -1,6 +1,85 @@ +Aufgabe 4 +========= + > module Aufgabe4 where -Aufgabe 4 finden befindet sich auf dem Branch `ghc-vis`. -Weitere Informationen in der README.md -> result = "foo" +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!" + diff --git a/src/Aufgabe4.md b/src/Aufgabe4.md index cbf40b0..7185466 100644 --- a/src/Aufgabe4.md +++ b/src/Aufgabe4.md @@ -1,6 +1,85 @@ +Aufgabe 4 +========= + > module Aufgabe4 where -Aufgabe 4 finden befindet sich auf dem Branch `ghc-vis`. -Weitere Informationen in der README.md -> result = "foo" +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!" + diff --git a/src/DataPB.hs b/src/DataPB.hs deleted file mode 100644 index 3ea8e5d..0000000 --- a/src/DataPB.hs +++ /dev/null @@ -1,9 +0,0 @@ -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")] - diff --git a/src/FunPB.hs b/src/FunPB.hs deleted file mode 100644 index 09d1eb3..0000000 --- a/src/FunPB.hs +++ /dev/null @@ -1,21 +0,0 @@ -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) diff --git a/stack.yaml b/stack.yaml index 8c4a91d..3ff8d70 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,5 +1,11 @@ +flags: {} extra-package-dbs: [] packages: - '.' -extra-deps: [] -resolver: lts-8.9 +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 diff --git a/test/Aufgabe1-Spec.hs b/test/Aufgabe1-Spec.hs deleted file mode 100644 index 2f66216..0000000 --- a/test/Aufgabe1-Spec.hs +++ /dev/null @@ -1,66 +0,0 @@ -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 diff --git a/test/Aufgabe2-Spec.hs b/test/Aufgabe2-Spec.hs deleted file mode 100644 index 12a1ad9..0000000 --- a/test/Aufgabe2-Spec.hs +++ /dev/null @@ -1,7 +0,0 @@ -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" \ No newline at end of file diff --git a/test/Aufgabe3-Spec.hs b/test/Aufgabe3-Spec.hs deleted file mode 100644 index 389e555..0000000 --- a/test/Aufgabe3-Spec.hs +++ /dev/null @@ -1,77 +0,0 @@ -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 \ No newline at end of file diff --git a/zettel2.cabal b/zettel2.cabal index 07b7d96..fe38512 100644 --- a/zettel2.cabal +++ b/zettel2.cabal @@ -18,74 +18,8 @@ cabal-version: >=1.10 -- to solve assignments library hs-source-dirs: src - exposed-modules: Lib - , DataPB - , AreaCode - , FunPB - , Aufgabe1 - , Aufgabe2 - , Aufgabe3 - , Aufgabe4 + exposed-modules: 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 @@ -94,15 +28,7 @@ executable aufgabe4 ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base , zettel2 - 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 + , ghc-vis default-language: Haskell2010 source-repository head