Added Aufgabe 4
This commit is contained in:
parent
0c89ace6c9
commit
aab564e716
29
.ghci
Normal file
29
.ghci
Normal file
@ -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
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
module Main where
|
|
||||||
|
|
||||||
import Aufgabe1
|
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = putStrLn result
|
|
@ -1,6 +0,0 @@
|
|||||||
module Main where
|
|
||||||
|
|
||||||
import Aufgabe2
|
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = putStrLn result
|
|
@ -1,6 +0,0 @@
|
|||||||
module Main where
|
|
||||||
|
|
||||||
import Aufgabe3
|
|
||||||
|
|
||||||
main :: IO ()
|
|
||||||
main = putStrLn result
|
|
2
install_dependencies.sh
Normal file
2
install_dependencies.sh
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
tar xf /media/remote/ygottschalk/.stack.tar.gz -C $HOME/
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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?"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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?"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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?"
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
147
src/Aufgabe3.hs
147
src/Aufgabe3.hs
@ -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")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
168
src/Aufgabe3.lhs
168
src/Aufgabe3.lhs
@ -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")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
171
src/Aufgabe3.md
171
src/Aufgabe3.md
@ -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")
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
@ -1,6 +1,85 @@
|
|||||||
|
-- Aufgabe 4
|
||||||
|
-- =========
|
||||||
|
|
||||||
module Aufgabe4 where
|
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!"
|
||||||
|
|
||||||
|
@ -1,6 +1,85 @@
|
|||||||
|
Aufgabe 4
|
||||||
|
=========
|
||||||
|
|
||||||
> module Aufgabe4 where
|
> 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!"
|
||||||
|
|
||||||
|
@ -1,6 +1,85 @@
|
|||||||
|
Aufgabe 4
|
||||||
|
=========
|
||||||
|
|
||||||
> module Aufgabe4 where
|
> 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!"
|
||||||
|
|
||||||
|
@ -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")]
|
|
||||||
|
|
21
src/FunPB.hs
21
src/FunPB.hs
@ -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)
|
|
10
stack.yaml
10
stack.yaml
@ -1,5 +1,11 @@
|
|||||||
|
flags: {}
|
||||||
extra-package-dbs: []
|
extra-package-dbs: []
|
||||||
packages:
|
packages:
|
||||||
- '.'
|
- '.'
|
||||||
extra-deps: []
|
extra-deps:
|
||||||
resolver: lts-8.9
|
- 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
|
||||||
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -18,74 +18,8 @@ cabal-version: >=1.10
|
|||||||
-- to solve assignments
|
-- to solve assignments
|
||||||
library
|
library
|
||||||
hs-source-dirs: src
|
hs-source-dirs: src
|
||||||
exposed-modules: Lib
|
exposed-modules: Aufgabe4
|
||||||
, DataPB
|
|
||||||
, AreaCode
|
|
||||||
, FunPB
|
|
||||||
, Aufgabe1
|
|
||||||
, Aufgabe2
|
|
||||||
, Aufgabe3
|
|
||||||
, Aufgabe4
|
|
||||||
build-depends: base >= 4.7 && < 5
|
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
|
default-language: Haskell2010
|
||||||
|
|
||||||
executable aufgabe4
|
executable aufgabe4
|
||||||
@ -94,15 +28,7 @@ executable aufgabe4
|
|||||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||||
build-depends: base
|
build-depends: base
|
||||||
, zettel2
|
, zettel2
|
||||||
default-language: Haskell2010
|
, ghc-vis
|
||||||
|
|
||||||
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
|
default-language: Haskell2010
|
||||||
|
|
||||||
source-repository head
|
source-repository head
|
||||||
|
Loading…
Reference in New Issue
Block a user