first commit, zettel2 without solutions
This commit is contained in:
commit
363316dc2e
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
dist
|
||||
dist-*
|
||||
cabal-dev
|
||||
*.o
|
||||
*.hi
|
||||
*.chi
|
||||
*.chs.h
|
||||
*.dyn_o
|
||||
*.dyn_hi
|
||||
.hpc
|
||||
.hsenv
|
||||
.cabal-sandbox/
|
||||
cabal.sandbox.config
|
||||
*.prof
|
||||
*.aux
|
||||
*.hp
|
||||
*.eventlog
|
||||
.stack-work/
|
||||
cabal.project.local
|
41
.travis.yml
Normal file
41
.travis.yml
Normal file
@ -0,0 +1,41 @@
|
||||
# This is the simple Travis configuration, which is intended for use
|
||||
# on applications which do not require cross-platform and
|
||||
# multiple-GHC-version support. For more information and other
|
||||
# options, see:
|
||||
#
|
||||
# https://docs.haskellstack.org/en/stable/travis_ci/
|
||||
#
|
||||
# Copy these contents into the root directory of your Github project in a file
|
||||
# named .travis.yml
|
||||
|
||||
# Use new container infrastructure to enable caching
|
||||
sudo: false
|
||||
|
||||
# Do not choose a language; we provide our own build tools.
|
||||
language: generic
|
||||
|
||||
# Caching so the next build will be fast too.
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.stack
|
||||
|
||||
# Ensure necessary system libraries are present
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libgmp-dev
|
||||
|
||||
before_install:
|
||||
# Download and unpack the stack executable
|
||||
- mkdir -p ~/.local/bin
|
||||
- export PATH=$HOME/.local/bin:$PATH
|
||||
- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'
|
||||
|
||||
install:
|
||||
# Build dependencies
|
||||
- stack --no-terminal --install-ghc test --only-dependencies
|
||||
|
||||
script:
|
||||
# Build the package, its tests, and its docs and run the tests
|
||||
- stack --no-terminal test --haddock --no-haddock-deps
|
||||
|
30
LICENSE
Normal file
30
LICENSE
Normal file
@ -0,0 +1,30 @@
|
||||
Copyright Author name here (c) 2017
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Author name here nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
6
app/Aufgabe1Main.hs
Normal file
6
app/Aufgabe1Main.hs
Normal file
@ -0,0 +1,6 @@
|
||||
module Main where
|
||||
|
||||
import Aufgabe1
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn result
|
6
app/Aufgabe2Main.hs
Normal file
6
app/Aufgabe2Main.hs
Normal file
@ -0,0 +1,6 @@
|
||||
module Main where
|
||||
|
||||
import Aufgabe2
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn result
|
6
app/Aufgabe3Main.hs
Normal file
6
app/Aufgabe3Main.hs
Normal file
@ -0,0 +1,6 @@
|
||||
module Main where
|
||||
|
||||
import Aufgabe3
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn result
|
6
app/Aufgabe4Main.hs
Normal file
6
app/Aufgabe4Main.hs
Normal file
@ -0,0 +1,6 @@
|
||||
module Main where
|
||||
|
||||
import Aufgabe4
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn result
|
27
src/AreaCode.hs
Normal file
27
src/AreaCode.hs
Normal file
@ -0,0 +1,27 @@
|
||||
module AreaCode (AreaCode,separateAreaCode) where
|
||||
|
||||
import qualified Data.Attoparsec.Text as A
|
||||
import Data.Attoparsec.Combinator
|
||||
import qualified Data.Text as T
|
||||
|
||||
type Number = String
|
||||
type Name = String
|
||||
type AreaCode = String
|
||||
|
||||
{-Area Code Parser-}
|
||||
|
||||
separateAreaCode :: Number -> (AreaCode,Number)
|
||||
separateAreaCode nr =
|
||||
case A.parse parseAreaCode (T.pack nr) of
|
||||
A.Done s ac -> (ac, T.unpack s)
|
||||
_ -> ("",nr)
|
||||
|
||||
parseAreaCode :: A.Parser String
|
||||
parseAreaCode = do
|
||||
many' (A.char ' ')
|
||||
A.char '('
|
||||
ac <- many1 $ A.satisfy (A.inClass "0123456789")
|
||||
A.char ')'
|
||||
many' (A.char ' ')
|
||||
return ac
|
||||
|
82
src/Aufgabe1.hs
Normal file
82
src/Aufgabe1.hs
Normal file
@ -0,0 +1,82 @@
|
||||
-- Aufgabe 1
|
||||
-- =========
|
||||
|
||||
module Aufgabe1 where
|
||||
|
||||
-- Functional phone book – Implementieren Sie ein Telefonbuch als Funktion.
|
||||
|
||||
type Number = String
|
||||
type Name = String
|
||||
type Entry = [Number]
|
||||
newtype PhoneBook = PB (Name -> Entry)
|
||||
|
||||
|
||||
-- Implementieren Sie die Funktion `usePB`, welche aus einem `PhoneBook`
|
||||
-- mit einem `Name` den zugehörigen `Entry` findet`
|
||||
|
||||
|
||||
usePB :: PhoneBook -> Name -> Entry
|
||||
usePB = undefined
|
||||
|
||||
|
||||
|
||||
-- Implementieren Sie eine `Monoid` Instanz für `PhoneBook`, um zu garantieren,
|
||||
-- dass `PhoneBook` ein leeres Element hat und eine Verkettungsfunktion, die
|
||||
-- zwei `PhoneBook`s in eines zusammenführt.
|
||||
|
||||
|
||||
instance Monoid PhoneBook where
|
||||
mempty = undefined
|
||||
mappend = undefined
|
||||
|
||||
|
||||
|
||||
-- Implementieren Sie eine Funktion `addEntry`, welche einem `PhoneBook` eine
|
||||
-- `Name` zu `Number` Verknüpfung hinzufügt, also für einen gegebenen Namen und
|
||||
-- eine Nummer einen Eintrag im Telefonbuch erstellt.
|
||||
|
||||
|
||||
addEntry :: Name -> Number -> PhoneBook -> PhoneBook
|
||||
addEntry = undefined
|
||||
|
||||
|
||||
|
||||
-- Implementieren Sie eine Funktion `delEntry`, die alle Nummern aus dem `PhoneBook`
|
||||
-- entfernt, die mit dem gegebenen `Name` assoziiert sind.
|
||||
-- Hinweis: "Entfernt" heißt streng genommen nur, dass die Nummern nicht mehr aus
|
||||
-- dem resultierenden Telefonbuch herausgesucht werden können
|
||||
|
||||
|
||||
delEntry :: Name -> PhoneBook -> PhoneBook
|
||||
delEntry = undefined
|
||||
|
||||
|
||||
-- Implementieren Sie eine Funktion `findInMult`, welche alle Einträge aus einer
|
||||
-- Liste von `PhoneBook`s sucht
|
||||
|
||||
|
||||
findInMult :: [PhoneBook] -> Name -> Entry
|
||||
findInMult = undefined
|
||||
|
||||
|
||||
result = "Wie war noch mal die Nummer von diesem Alonzo Church? Vielleicht kann der mir weiterhelfen.. \n"
|
||||
++ (show $ findInMult [pb2,pb3] "Alonzo Church") ++ "\n"
|
||||
where pb1 = addEntry "Alonzo Church" "(0123) 73645362" mempty
|
||||
pb2 = delEntry "Alonzo Church" pb1
|
||||
pb3 = addEntry "Haskell Brooks Curry" "(0167) 987761262" (mappend pb1 pb2)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
72
src/Aufgabe1.lhs
Normal file
72
src/Aufgabe1.lhs
Normal file
@ -0,0 +1,72 @@
|
||||
Aufgabe 1
|
||||
=========
|
||||
|
||||
> module Aufgabe1 where
|
||||
|
||||
Functional phone book – Implementieren Sie ein Telefonbuch als Funktion.
|
||||
|
||||
> type Number = String
|
||||
> type Name = String
|
||||
> type Entry = [Number]
|
||||
> newtype PhoneBook = PB (Name -> Entry)
|
||||
|
||||
|
||||
Implementieren Sie die Funktion `usePB`, welche aus einem `PhoneBook`
|
||||
mit einem `Name` den zugehörigen `Entry` findet`
|
||||
|
||||
|
||||
> usePB :: PhoneBook -> Name -> Entry
|
||||
> usePB = undefined
|
||||
|
||||
|
||||
|
||||
Implementieren Sie eine `Monoid` Instanz für `PhoneBook`, um zu garantieren,
|
||||
dass `PhoneBook` ein leeres Element hat und eine Verkettungsfunktion, die
|
||||
zwei `PhoneBook`s in eines zusammenführt.
|
||||
|
||||
|
||||
> instance Monoid PhoneBook where
|
||||
> mempty = undefined
|
||||
> mappend = undefined
|
||||
|
||||
|
||||
|
||||
Implementieren Sie eine Funktion `addEntry`, welche einem `PhoneBook` eine
|
||||
`Name` zu `Number` Verknüpfung hinzufügt, also für einen gegebenen Namen und
|
||||
eine Nummer einen Eintrag im Telefonbuch erstellt.
|
||||
|
||||
|
||||
> addEntry :: Name -> Number -> PhoneBook -> PhoneBook
|
||||
> addEntry = undefined
|
||||
|
||||
|
||||
|
||||
Implementieren Sie eine Funktion `delEntry`, die alle Nummern aus dem `PhoneBook`
|
||||
entfernt, die mit dem gegebenen `Name` assoziiert sind.
|
||||
Hinweis: "Entfernt" heißt streng genommen nur, dass die Nummern nicht mehr aus
|
||||
dem resultierenden Telefonbuch herausgesucht werden können
|
||||
|
||||
|
||||
> delEntry :: Name -> PhoneBook -> PhoneBook
|
||||
> delEntry = undefined
|
||||
|
||||
|
||||
|
||||
Implementieren Sie eine Funktion `findInMult`, welche alle Einträge aus einer
|
||||
Liste von `PhoneBook`s sucht
|
||||
|
||||
|
||||
> findInMult :: [PhoneBook] -> Name -> Entry
|
||||
> findInMult = undefined
|
||||
|
||||
|
||||
|
||||
> result = "Wie war noch mal die Nummer von diesem Alonzo Church? Vielleicht kann der mir weiterhelfen.. \n"
|
||||
> ++ (show $ findInMult [pb2,pb3] "Alonzo Church") ++ "\n"
|
||||
> where pb1 = addEntry "Alonzo Church" "(0123) 73645362" mempty
|
||||
> pb2 = delEntry "Alonzo Church" pb1
|
||||
> pb3 = addEntry "Haskell Brooks Curry" "(0167) 987761262" (mappend pb1 pb2)
|
||||
|
||||
|
||||
|
||||
|
79
src/Aufgabe1.md
Normal file
79
src/Aufgabe1.md
Normal file
@ -0,0 +1,79 @@
|
||||
Aufgabe 1
|
||||
=========
|
||||
|
||||
```haskell
|
||||
module Aufgabe1 where
|
||||
```
|
||||
|
||||
Functional phone book – Implementieren Sie ein Telefonbuch als Funktion.
|
||||
|
||||
```haskell
|
||||
type Number = String
|
||||
type Name = String
|
||||
type Entry = [Number]
|
||||
newtype PhoneBook = PB (Name -> Entry)
|
||||
```
|
||||
|
||||
Implementieren Sie die Funktion `usePB`, welche aus einem `PhoneBook`
|
||||
mit einem `Name` den zugehörigen `Entry` findet`
|
||||
|
||||
```haskell
|
||||
usePB :: PhoneBook -> Name -> Entry
|
||||
usePB = undefined
|
||||
```
|
||||
|
||||
|
||||
Implementieren Sie eine `Monoid` Instanz für `PhoneBook`, um zu garantieren,
|
||||
dass `PhoneBook` ein leeres Element hat und eine Verkettungsfunktion, die
|
||||
zwei `PhoneBook`s in eines zusammenführt.
|
||||
|
||||
```haskell
|
||||
instance Monoid PhoneBook where
|
||||
mempty = undefined
|
||||
mappend pb1 pb2 = undefined
|
||||
```
|
||||
|
||||
|
||||
Implementieren Sie eine Funktion `addEntry`, welche einem `PhoneBook` eine
|
||||
`Name` zu `Number` Verknüpfung hinzufügt, also für einen gegebenen Namen und
|
||||
eine Nummer einen Eintrag im Telefonbuch erstellt.
|
||||
|
||||
```haskell
|
||||
addEntry :: Name -> Number -> PhoneBook -> PhoneBook
|
||||
addEntry n nr pb = undefined
|
||||
```
|
||||
|
||||
|
||||
Implementieren Sie eine Funktion `delEntry`, die alle Nummern aus dem `PhoneBook`
|
||||
entfernt, die mit dem gegebenen `Name` assoziiert sind.
|
||||
Hinweis: "Entfernt" heißt streng genommen nur, dass die Nummern nicht mehr aus
|
||||
dem resultierenden Telefonbuch herausgesucht werden können
|
||||
|
||||
```haskell
|
||||
delEntry :: Name -> PhoneBook -> PhoneBook
|
||||
delEntry n pb = undefined
|
||||
```
|
||||
|
||||
|
||||
Implementieren Sie eine Funktion `findInMult`, welche alle Einträge aus einer
|
||||
Liste von `PhoneBook`s sucht
|
||||
|
||||
```haskell
|
||||
findInMult :: [PhoneBook] -> Name -> Entry
|
||||
findInMult = undefined
|
||||
```
|
||||
|
||||
```haskell
|
||||
result = "Wie war noch mal die Nummer von diesem Alonzo Church? Vielleicht kann der mir weiterhelfen.. \n"
|
||||
++ (show $ findInMult [pb2,pb3] "Alonzo Church") ++ "\n"
|
||||
where pb1 = addEntry "Alonzo Church" "(0123) 73645362" mempty
|
||||
pb2 = delEntry "Alonzo Church" pb1
|
||||
pb3 = addEntry "Haskell Brooks Curry" "(0167) 987761262" (mappend pb1 pb2)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
41
src/Aufgabe2.hs
Normal file
41
src/Aufgabe2.hs
Normal file
@ -0,0 +1,41 @@
|
||||
-- Aufgabe 2
|
||||
-- =========
|
||||
|
||||
module Aufgabe2 where
|
||||
|
||||
-- Besser und allgemeiner
|
||||
-- ----------------------
|
||||
|
||||
-- Vereinfachen und verallgemeinern sie folgenden Ausdrücke so weit wie
|
||||
-- möglich. Geben Sie die dadurch entstehenden Typsignaturen und
|
||||
-- Funktionsdefinitionen an. Bedenken Sie, dass wenn sie auf eine Typklasse
|
||||
-- abstrahieren, Sie die gesamten Gesetze der Typklasse benutzen können.
|
||||
|
||||
-- Kann die Funktion nachher mehr als vorher?
|
||||
|
||||
-- *Bonus*: Hat sich an der Laufzeit etwas verändert?
|
||||
|
||||
|
||||
mystery1 :: [[a]] -> [[a]]
|
||||
mystery1 = map (++[])
|
||||
|
||||
mystery2 :: (Int -> Bool)
|
||||
-> Maybe (Either String Int)
|
||||
-> Maybe (Either String Bool)
|
||||
mystery2 f (Just (Right a)) = Just . Right . f $ a
|
||||
mystery2 _ (Just (Left b)) = Just (Left b)
|
||||
mystery2 _ Nothing = Nothing
|
||||
|
||||
mystery3 :: (Eq a) => a -> a -> a -> Bool
|
||||
mystery3 x y z
|
||||
| y == z = True
|
||||
| z == y && y == x = True
|
||||
| x /= z = False
|
||||
| y /= x = False
|
||||
| z /= y || y /= x = True
|
||||
| otherwise = False
|
||||
|
||||
result = "foo?"
|
||||
|
||||
|
||||
|
45
src/Aufgabe2.lhs
Normal file
45
src/Aufgabe2.lhs
Normal file
@ -0,0 +1,45 @@
|
||||
Aufgabe 2
|
||||
=========
|
||||
|
||||
> module Aufgabe2 where
|
||||
|
||||
Besser und allgemeiner
|
||||
----------------------
|
||||
|
||||
Vereinfachen und verallgemeinern sie folgenden Ausdrücke so weit wie
|
||||
möglich. Geben Sie die dadurch entstehenden Typsignaturen und
|
||||
Funktionsdefinitionen an. Bedenken Sie, dass wenn sie auf eine Typklasse
|
||||
abstrahieren, Sie die gesamten Gesetze der Typklasse benutzen können.
|
||||
|
||||
Kann die Funktion nachher mehr als vorher?
|
||||
|
||||
*Bonus*: Hat sich an der Laufzeit etwas verändert?
|
||||
|
||||
|
||||
> mystery1 :: [[a]] -> [[a]]
|
||||
> mystery1 = map (++[])
|
||||
|
||||
|
||||
> mystery2 :: (Int -> Bool)
|
||||
> -> Maybe (Either String Int)
|
||||
> -> Maybe (Either String Bool)
|
||||
> mystery2 f (Just (Right a)) = Just . Right . f $ a
|
||||
> mystery2 _ (Just (Left b)) = Just (Left b)
|
||||
> mystery2 _ Nothing = Nothing
|
||||
|
||||
|
||||
> mystery3 :: (Eq a) => a -> a -> a -> Bool
|
||||
> mystery3 x y z
|
||||
> | y == z = True
|
||||
> | z == y && y == x = True
|
||||
> | x /= z = False
|
||||
> | y /= x = False
|
||||
> | z /= y || y /= x = True
|
||||
> | otherwise = False
|
||||
|
||||
|
||||
|
||||
> result = "foo?"
|
||||
|
||||
|
||||
|
47
src/Aufgabe2.md
Normal file
47
src/Aufgabe2.md
Normal file
@ -0,0 +1,47 @@
|
||||
Aufgabe 2
|
||||
=========
|
||||
|
||||
```haskell
|
||||
module Aufgabe2 where
|
||||
```
|
||||
|
||||
Besser und allgemeiner
|
||||
----------------------
|
||||
|
||||
Vereinfachen und verallgemeinern sie folgenden Ausdrücke so weit wie
|
||||
möglich. Geben Sie die dadurch entstehenden Typsignaturen und
|
||||
Funktionsdefinitionen an. Bedenken Sie, dass wenn sie auf eine Typklasse
|
||||
abstrahieren, Sie die gesamten Gesetze der Typklasse benutzen können.
|
||||
|
||||
Kann die Funktion nachher mehr als vorher?
|
||||
|
||||
*Bonus*: Hat sich an der Laufzeit etwas verändert?
|
||||
|
||||
```haskell
|
||||
mystery1 :: [[a]] -> [[a]]
|
||||
mystery1 = map (++[])
|
||||
|
||||
|
||||
mystery2 :: (Int -> Bool)
|
||||
-> Maybe (Either String Int)
|
||||
-> Maybe (Either String Bool)
|
||||
mystery2 f (Just (Right a)) = Just . Right . f $ a
|
||||
mystery2 _ (Just (Left b)) = Just (Left b)
|
||||
mystery2 _ Nothing = Nothing
|
||||
|
||||
|
||||
mystery3 :: (Eq a) => a -> a -> a -> Bool
|
||||
mystery3 x y z
|
||||
| y == z = True
|
||||
| z == y && y == x = True
|
||||
| x /= z = False
|
||||
| y /= x = False
|
||||
| z /= y || y /= x = True
|
||||
| otherwise = False
|
||||
|
||||
|
||||
|
||||
result = "foo?"
|
||||
```
|
||||
|
||||
|
147
src/Aufgabe3.hs
Normal file
147
src/Aufgabe3.hs
Normal file
@ -0,0 +1,147 @@
|
||||
-- Aufgabe 3
|
||||
-- =========
|
||||
|
||||
module Aufgabe3 where
|
||||
|
||||
import FunPB
|
||||
import DataPB
|
||||
import AreaCode
|
||||
import Data.Char
|
||||
|
||||
-- Functor – ein Container?
|
||||
-- --------------------------
|
||||
|
||||
-- Zur Erinnerung:
|
||||
|
||||
|
||||
-- class Functor f where
|
||||
-- fmap :: (a -> b) -> f a -> f b
|
||||
|
||||
-- Aus der Vorlesung 2 kennen Sie bereits die `Functor`-Instanzen für `[]`, `Identity`
|
||||
-- und einen binären Baum. Außerdem haben Sie gelernt, dass Sie auch für Ihre eigenen
|
||||
-- Typen `Functor`-Instanzen definieren können. Eine Intuition dafür, ob sich für einen
|
||||
-- Typ eine `Functor`-Instanz schreiben lässt, erhalten Sie, indem Sie sich fragen, ob
|
||||
-- der Typ "eine Art Container" ist, auf deren Inhalte sich Funktionen (a -> b) anwenden
|
||||
-- lassen. Was bedeutet dies in Haskell-Syntax? Hierfür ist es dienlich, sich den
|
||||
-- `type constructor` des betreffenden Datentyps anzuschauen. Handelt es sich um einen
|
||||
-- polymorphen Datentyp stehen die Chancen gut, dass es ein `Functor` ist.
|
||||
|
||||
-- data Bool = False | True
|
||||
|
||||
-- data Maybe a = Nothing | Just a
|
||||
|
||||
-- data (,) a b = (a,b)
|
||||
|
||||
-- `Bool` ist offenbar kein `Functor`, denn der Typkonstruktor `Bool` hat keine Parameter –
|
||||
-- hier ist nur Platz für True und False. `Maybe a` dagegen hat einen Parameter, einen freien
|
||||
-- Slot für alles mögliche. Der Tupeltyp `(,) a b` hat sogar zwei Parameter – er kann Dinge von
|
||||
-- zwei verschiedenen Typen enthalten. Hier stellt sich die Frage, für welchen Container die
|
||||
-- Functorinstanz definiert ist. Ähnlich wie Funktionen, lassen sich auch Typkonstruktoren
|
||||
-- partiell anwenden. Für die Instanziierung werden dem Typkonstruktor daher alle bis auf ein
|
||||
-- Parameter übergeben. Dieser letzte, freie Parameter legt dann den Inhalt des "Container"
|
||||
-- fest. Beispiel:
|
||||
|
||||
-- instance Functor ((,) a) where --Die Functor-Instanz ist für (,) a definiert
|
||||
-- fmap f (x,y) = (x, f y) --Also wird über Tupelslot 2 "gemapt"
|
||||
|
||||
-- Implementieren Sie `Functor`-Instanzen für die folgenden Datentypen:
|
||||
|
||||
|
||||
data Vielleicht a = Nichts | Etwas a
|
||||
deriving (Show,Eq)
|
||||
|
||||
instance Functor Vielleicht where
|
||||
fmap = undefined
|
||||
|
||||
|
||||
data Entweder a b = Jenes a | Dieses b
|
||||
deriving (Show,Eq)
|
||||
|
||||
instance Functor (Entweder a) where
|
||||
fmap = undefined
|
||||
|
||||
|
||||
data Konstant a b = Konstant a
|
||||
deriving (Show,Eq)
|
||||
|
||||
instance Functor (Konstant a) where
|
||||
fmap = undefined
|
||||
|
||||
|
||||
-- Achtung: Die "Container"-Metapher hat ihre Grenzen. Betrachten Sie hierzu noch einmal den
|
||||
-- Datentyp Pred a von Zettel 1: `data Pred a = Pred (\a -> Bool)`.
|
||||
|
||||
data Pred a = Pred (a -> Bool)
|
||||
runPred :: Pred a -> (a -> Bool)
|
||||
runPred (Pred p) = p
|
||||
|
||||
-- `Pred a` macht den Anschein als handele es sich auch hier um einen Container mit Inhalt a.
|
||||
-- Trotzdem lässt sich `Functor` hierfür nicht instanziieren. Der Unterschied liegt darin,
|
||||
-- dass der Typaramter `a` als Input und nicht als Ergebnis in der vom Konstruktor `Pred`
|
||||
-- "eingepackten" Berechnung auftaucht. Allerdings lässt sich hier auf eine sehr ähnliche
|
||||
-- Eigenschaft abstrahieren, die wir für's Erste `InputFunctor` nennen wollen.
|
||||
|
||||
class InputFunctor f where
|
||||
inputmap :: (a -> b) -> f b -> f a
|
||||
|
||||
-- Schreiben Sie eine `InputFunctor`-Instanz für `Pred a`.
|
||||
|
||||
instance InputFunctor Pred where
|
||||
inputmap = undefined
|
||||
|
||||
-- Hiermit lässt sich nun bequem die folgende Funktion definieren, welche aus einem
|
||||
-- `Pred Int` ein `Pred String` macht, das prüft, ob ein Eingabestring wenigstens die Länge 5 hat.
|
||||
|
||||
atLeast5 :: Pred Int
|
||||
atLeast5 = Pred $ (\x -> x>=5)
|
||||
|
||||
atLeast5Char :: Pred String
|
||||
atLeast5Char = inputmap length atLeast5
|
||||
|
||||
-- Functorial phone book
|
||||
-- ---------------------
|
||||
|
||||
-- Jetzt noch einmal zurück zu PhoneBook aus Aufgabe 1.
|
||||
|
||||
type Number = String
|
||||
type Name = String
|
||||
type Entry = [Number]
|
||||
|
||||
newtype PhoneBook = PB (Name -> Entry)
|
||||
|
||||
-- `PhoneBook` hat keinen Parameter, aber die allgemeinere Version `FunPB` hat sogar zwei:
|
||||
-- data FunPB a b = FunPB (a -> (a,[b]))
|
||||
|
||||
-- Beachten Sie, dass sich auch der Rückgabetyp ein wenig unterscheidet. Die Idee ist,
|
||||
-- dass FunPB zusätzlich zu den assoziierten `Number`s (angenommen `b` ist `Number`) auch
|
||||
-- den gesuchten `Name` (angenommen `a` ist `Name`) zurückgibt.
|
||||
|
||||
-- Implementieren Sie eine `Functor`-Instanz für `FunPB`.
|
||||
-- Hinweis: Sie können benutzen, dass für `[]`, `((,) a)` und sogar für den "function arrow"
|
||||
-- `((->) a)` bereits `Functor`-Instanzen in der [`GHC.Base`](https://hackage.haskell.org/package/base "GHC.Base") existieren.
|
||||
|
||||
instance Functor (FunPB a) where
|
||||
fmap = undefined
|
||||
|
||||
-- Die Functor-Instanz erlaubt uns nun die Funktionen
|
||||
-- `separateAreaCode :: Number -> (AreaCode,Number)` und `snd` zu verwenden, um ein
|
||||
-- TelefonBuch mit separiertem bzw. ganz ohne AreaCode zu erhalten.
|
||||
|
||||
areaCodeFunPB :: FunPB Name String -> FunPB Name (AreaCode,Number)
|
||||
areaCodeFunPB = fmap separateAreaCode
|
||||
|
||||
withoutAreaCodeFunPB :: FunPB Name Number -> FunPB Name Number
|
||||
withoutAreaCodeFunPB = fmap (snd.separateAreaCode)
|
||||
|
||||
|
||||
result = "Suche \"Paula\" in (FunPB Name Number): \n"
|
||||
++ (show $ runFunPB (dataToFunPB simpleData) "Paula") ++ "\n"
|
||||
++ "Suche \"Paula\" in (FunPB Name (AreaCode,Number)): \n"
|
||||
++ (show $ runFunPB (areaCodeFunPB $ dataToFunPB simpleData) "Paula") ++ "\n"
|
||||
++ "Suche \"Paula\" in (FunPB Name Number) ohne Vorwahl: \n"
|
||||
++ (show $ runFunPB (withoutAreaCodeFunPB $ dataToFunPB simpleData) "Paula")
|
||||
|
||||
|
||||
|
||||
|
||||
|
168
src/Aufgabe3.lhs
Normal file
168
src/Aufgabe3.lhs
Normal file
@ -0,0 +1,168 @@
|
||||
Aufgabe 3
|
||||
=========
|
||||
|
||||
> module Aufgabe3 where
|
||||
|
||||
> import FunPB
|
||||
> import DataPB
|
||||
> import AreaCode
|
||||
> import Data.Char
|
||||
|
||||
`Functor` – ein Container?
|
||||
--------------------------
|
||||
|
||||
Zur Erinnerung:
|
||||
|
||||
class Functor f where
|
||||
fmap :: (a -> b) -> f a -> f b
|
||||
|
||||
Aus der Vorlesung 2 kennen Sie bereits die `Functor`-Instanzen für `[]`, `Identity`
|
||||
und einen binären Baum. Außerdem haben Sie gelernt, dass Sie auch für Ihre eigenen
|
||||
Typen `Functor`-Instanzen definieren können. Eine Intuition dafür, ob sich für einen
|
||||
Typ eine `Functor`-Instanz schreiben lässt, erhalten Sie, indem Sie sich fragen, ob
|
||||
der Typ "eine Art Container" ist, auf deren Inhalte sich Funktionen (a -> b) anwenden
|
||||
lassen. Was bedeutet dies in Haskell-Syntax? Hierfür ist es dienlich, sich den
|
||||
`type constructor` des betreffenden Datentyps anzuschauen. Handelt es sich um einen
|
||||
polymorphen Datentyp stehen die Chancen gut, dass es ein `Functor` ist.
|
||||
|
||||
|
||||
data Bool = False | True
|
||||
|
||||
data Maybe a = Nothing | Just a
|
||||
|
||||
data (,) a b = (a,b)
|
||||
|
||||
|
||||
`Bool` ist offenbar kein `Functor`, denn der Typkonstruktor `Bool` hat keine Parameter –
|
||||
hier ist nur Platz für True und False. `Maybe a` dagegen hat einen Parameter, einen freien
|
||||
Slot für alles mögliche. Der Tupeltyp `(,) a b` hat sogar zwei Parameter – er kann Dinge von
|
||||
zwei verschiedenen Typen enthalten. Hier stellt sich die Frage, für welchen Container die
|
||||
Functorinstanz definiert ist. Ähnlich wie Funktionen, lassen sich auch Typkonstruktoren
|
||||
partiell anwenden. Für die Instanziierung werden dem Typkonstruktor daher alle bis auf ein
|
||||
Parameter übergeben. Dieser letzte, freie Parameter legt dann den Inhalt des "Container"
|
||||
fest. Beispiel:
|
||||
|
||||
|
||||
instance Functor ((,) a) where --Die Functor-Instanz ist für (,) a definiert
|
||||
fmap f (x,y) = (x, f y) --Also wird über Tupelslot 2 "gemapt"
|
||||
|
||||
|
||||
Implementieren Sie `Functor`-Instanzen für die folgenden Datentypen:
|
||||
|
||||
|
||||
> data Vielleicht a = Nichts | Etwas a
|
||||
> deriving (Show,Eq)
|
||||
|
||||
> instance Functor Vielleicht where
|
||||
> fmap = undefined
|
||||
|
||||
|
||||
> data Entweder a b = Jenes a | Dieses b
|
||||
> deriving (Show,Eq)
|
||||
|
||||
> instance Functor (Entweder a) where
|
||||
> fmap = undefined
|
||||
|
||||
|
||||
> data Konstant a b = Konstant a
|
||||
> deriving (Show,Eq)
|
||||
|
||||
> instance Functor (Konstant a) where
|
||||
> fmap = undefined
|
||||
|
||||
|
||||
|
||||
Achtung: Die "Container"-Metapher hat ihre Grenzen. Betrachten Sie hierzu noch einmal den
|
||||
Datentyp Pred a von Zettel 1: `data Pred a = Pred (\a -> Bool)`.
|
||||
|
||||
|
||||
> data Pred a = Pred (a -> Bool)
|
||||
> runPred :: Pred a -> (a -> Bool)
|
||||
> runPred (Pred p) = p
|
||||
|
||||
|
||||
`Pred a` macht den Anschein als handele es sich auch hier um einen Container mit Inhalt a.
|
||||
Trotzdem lässt sich `Functor` hierfür nicht instanziieren. Der Unterschied liegt darin,
|
||||
dass der Typaramter `a` als Input und nicht als Ergebnis in der vom Konstruktor `Pred`
|
||||
"eingepackten" Berechnung auftaucht. Allerdings lässt sich hier auf eine sehr ähnliche
|
||||
Eigenschaft abstrahieren, die wir für's Erste `InputFunctor` nennen wollen.
|
||||
```
|
||||
|
||||
> class InputFunctor f where
|
||||
> inputmap :: (a -> b) -> f b -> f a
|
||||
|
||||
|
||||
Schreiben Sie eine `InputFunctor`-Instanz für `Pred a`.
|
||||
|
||||
|
||||
> instance InputFunctor Pred where
|
||||
> inputmap = undefined
|
||||
|
||||
|
||||
Hiermit lässt sich nun bequem die folgende Funktion definieren, welche aus einem
|
||||
`Pred Int` ein `Pred String` macht, das prüft, ob ein Eingabestring wenigstens die Länge 5 hat.
|
||||
|
||||
|
||||
> atLeast5 :: Pred Int
|
||||
> atLeast5 = Pred $ (\x -> x>=5)
|
||||
|
||||
> atLeast5Char :: Pred String
|
||||
> atLeast5Char = inputmap length atLeast5
|
||||
|
||||
|
||||
Functorial phone book
|
||||
---------------------
|
||||
|
||||
Jetzt noch einmal zurück zu PhoneBook aus Aufgabe 1.
|
||||
|
||||
|
||||
> type Number = String
|
||||
> type Name = String
|
||||
> type Entry = [Number]
|
||||
|
||||
> newtype PhoneBook = PB (Name -> Entry)
|
||||
|
||||
|
||||
`PhoneBook` hat keinen Parameter, aber die allgemeinere Version `FunPB` hat sogar zwei:
|
||||
|
||||
|
||||
data FunPB a b = FunPB (a -> (a,[b]))
|
||||
|
||||
|
||||
Beachten Sie, dass sich auch der Rückgabetyp ein wenig unterscheidet. Die Idee ist,
|
||||
dass FunPB zusätzlich zu den assoziierten `Number`s (angenommen `b` ist `Number`) auch
|
||||
den gesuchten `Name` (angenommen `a` ist `Name`) zurückgibt.
|
||||
|
||||
Implementieren Sie eine `Functor`-Instanz für `FunPB`.
|
||||
Hinweis: Sie können benutzen, dass für `[]`, `((,) a)` und sogar für den "function arrow"
|
||||
`((->) a)` bereits `Functor`-Instanzen in der [`GHC.Base`](https://hackage.haskell.org/package/base "GHC.Base") existieren.
|
||||
|
||||
|
||||
> instance Functor (FunPB a) where
|
||||
> fmap = undefined
|
||||
|
||||
|
||||
Die Functor-Instanz erlaubt uns nun die Funktionen
|
||||
`separateAreaCode :: Number -> (AreaCode,Number)` und `snd` zu verwenden, um ein
|
||||
TelefonBuch mit separiertem bzw. ganz ohne AreaCode zu erhalten.
|
||||
|
||||
|
||||
> areaCodeFunPB :: FunPB Name String -> FunPB Name (AreaCode,Number)
|
||||
> areaCodeFunPB = fmap separateAreaCode
|
||||
|
||||
> withoutAreaCodeFunPB :: FunPB Name Number -> FunPB Name Number
|
||||
> withoutAreaCodeFunPB = fmap (snd.separateAreaCode)
|
||||
|
||||
|
||||
|
||||
|
||||
> result = "Suche \"Paula\" in (FunPB Name Number): \n"
|
||||
> ++ (show $ runFunPB (dataToFunPB simpleData) "Paula") ++ "\n"
|
||||
> ++ "Suche \"Paula\" in (FunPB Name (AreaCode,Number)): \n"
|
||||
> ++ (show $ runFunPB (areaCodeFunPB $ dataToFunPB simpleData) "Paula") ++ "\n"
|
||||
> ++ "Suche \"Paula\" in (FunPB Name Number) ohne Vorwahl: \n"
|
||||
> ++ (show $ runFunPB (withoutAreaCodeFunPB $ dataToFunPB simpleData) "Paula")
|
||||
|
||||
|
||||
|
||||
|
171
src/Aufgabe3.md
Normal file
171
src/Aufgabe3.md
Normal file
@ -0,0 +1,171 @@
|
||||
Aufgabe 3
|
||||
=========
|
||||
|
||||
```haskell
|
||||
module Aufgabe3 where
|
||||
|
||||
import FunPB
|
||||
import DataPB
|
||||
import AreaCode
|
||||
import Data.Char
|
||||
```
|
||||
|
||||
`Functor` – ein Container?
|
||||
--------------------------
|
||||
|
||||
Zur Erinnerung:
|
||||
|
||||
```haskell
|
||||
class Functor f where
|
||||
fmap :: (a -> b) -> f a -> f b
|
||||
```
|
||||
|
||||
Aus der Vorlesung 2 kennen Sie bereits die `Functor`-Instanzen für `[]`, `Identity`
|
||||
und einen binären Baum. Außerdem haben Sie gelernt, dass Sie auch für Ihre eigenen
|
||||
Typen `Functor`-Instanzen definieren können. Eine Intuition dafür, ob sich für einen
|
||||
Typ eine `Functor`-Instanz schreiben lässt, erhalten Sie, indem Sie sich fragen, ob
|
||||
der Typ "eine Art Container" ist, auf deren Inhalte sich Funktionen (a -> b) anwenden
|
||||
lassen. Was bedeutet dies in Haskell-Syntax? Hierfür ist es dienlich, sich den
|
||||
`type constructor` des betreffenden Datentyps anzuschauen. Handelt es sich um einen
|
||||
polymorphen Datentyp stehen die Chancen gut, dass es ein `Functor` ist.
|
||||
|
||||
```haskell
|
||||
data Bool = False | True
|
||||
|
||||
data Maybe a = Nothing | Just a
|
||||
|
||||
data (,) a b = (a,b)
|
||||
```
|
||||
|
||||
`Bool` ist offenbar kein `Functor`, denn der Typkonstruktor `Bool` hat keine Parameter –
|
||||
hier ist nur Platz für True und False. `Maybe a` dagegen hat einen Parameter, einen freien
|
||||
Slot für alles mögliche. Der Tupeltyp `(,) a b` hat sogar zwei Parameter – er kann Dinge von
|
||||
zwei verschiedenen Typen enthalten. Hier stellt sich die Frage, für welchen Container die
|
||||
Functorinstanz definiert ist. Ähnlich wie Funktionen, lassen sich auch Typkonstruktoren
|
||||
partiell anwenden. Für die Instanziierung werden dem Typkonstruktor daher alle bis auf ein
|
||||
Parameter übergeben. Dieser letzte, freie Parameter legt dann den Inhalt des "Container"
|
||||
fest. Beispiel:
|
||||
|
||||
```haskell
|
||||
instance Functor ((,) a) where --Die Functor-Instanz ist für (,) a definiert
|
||||
fmap f (x,y) = (x, f y) --Also wird über Tupelslot 2 "gemapt"
|
||||
```
|
||||
|
||||
Implementieren Sie `Functor`-Instanzen für die folgenden Datentypen:
|
||||
|
||||
```haskell
|
||||
data Vielleicht a = Nichts | Etwas a
|
||||
deriving (Show,Eq)
|
||||
|
||||
instance Functor Vielleicht where
|
||||
fmap = undefined
|
||||
|
||||
|
||||
data Entweder a b = Jenes a | Dieses b
|
||||
deriving (Show,Eq)
|
||||
|
||||
instance Functor (Entweder a) where
|
||||
fmap = undefined
|
||||
|
||||
|
||||
data Konstant a b = Konstant a
|
||||
deriving (Show,Eq)
|
||||
|
||||
instance Functor (Konstant a) where
|
||||
fmap = undefined
|
||||
```
|
||||
|
||||
Achtung: Die "Container"-Metapher hat ihre Grenzen. Betrachten Sie hierzu noch einmal den
|
||||
Datentyp Pred a von Zettel 1: `data Pred a = Pred (\a -> Bool)`.
|
||||
|
||||
```haskell
|
||||
data Pred a = Pred (a -> Bool)
|
||||
runPred :: Pred a -> (a -> Bool)
|
||||
runPred (Pred p) = p
|
||||
```
|
||||
|
||||
`Pred a` macht den Anschein als handele es sich auch hier um einen Container mit Inhalt a.
|
||||
Trotzdem lässt sich `Functor` hierfür nicht instanziieren. Der Unterschied liegt darin,
|
||||
dass der Typaramter `a` als Input und nicht als Ergebnis in der vom Konstruktor `Pred`
|
||||
"eingepackten" Berechnung auftaucht. Allerdings lässt sich hier auf eine sehr ähnliche
|
||||
Eigenschaft abstrahieren, die wir für's Erste `InputFunctor` nennen wollen.
|
||||
|
||||
```haskell
|
||||
class InputFunctor f where
|
||||
inputmap :: (a -> b) -> f b -> f a
|
||||
```
|
||||
|
||||
Schreiben Sie eine `InputFunctor`-Instanz für `Pred a`.
|
||||
|
||||
```haskell
|
||||
instance InputFunctor Pred where
|
||||
inputmap = undefined
|
||||
```
|
||||
|
||||
Hiermit lässt sich nun bequem die folgende Funktion definieren, welche aus einem
|
||||
`Pred Int` ein `Pred String` macht, das prüft, ob ein Eingabestring wenigstens die Länge 5 hat.
|
||||
|
||||
```haskell
|
||||
atLeast5 :: Pred Int
|
||||
atLeast5 = Pred $ (\x -> x>=5)
|
||||
|
||||
atLeast5Char :: Pred String
|
||||
atLeast5Char = inputmap length atLeast5
|
||||
```
|
||||
|
||||
Functorial phone book
|
||||
---------------------
|
||||
|
||||
Jetzt noch einmal zurück zu PhoneBook aus Aufgabe 1.
|
||||
|
||||
```haskell
|
||||
type Number = String
|
||||
type Name = String
|
||||
type Entry = [Number]
|
||||
|
||||
newtype PhoneBook = PB (Name -> Entry)
|
||||
```
|
||||
|
||||
`PhoneBook` hat keinen Parameter, aber die allgemeinere Version `FunPB` hat sogar zwei:
|
||||
|
||||
```haskell
|
||||
data FunPB a b = FunPB (a -> (a,[b]))
|
||||
```
|
||||
|
||||
Beachten Sie, dass sich auch der Rückgabetyp ein wenig unterscheidet. Die Idee ist,
|
||||
dass FunPB zusätzlich zu den assoziierten `Number`s (angenommen `b` ist `Number`) auch
|
||||
den gesuchten `Name` (angenommen `a` ist `Name`) zurückgibt.
|
||||
|
||||
Implementieren Sie eine `Functor`-Instanz für `FunPB`.
|
||||
Hinweis: Sie können benutzen, dass für `[]`, `((,) a)` und sogar für den "function arrow"
|
||||
`((->) a)` bereits `Functor`-Instanzen in der [`GHC.Base`](https://hackage.haskell.org/package/base "GHC.Base") existieren.
|
||||
|
||||
```haskell
|
||||
instance Functor (FunPB a) where
|
||||
fmap = undefined
|
||||
```
|
||||
|
||||
Die Functor-Instanz erlaubt uns nun die Funktionen
|
||||
`separateAreaCode :: Number -> (AreaCode,Number)` und `snd` zu verwenden, um ein
|
||||
TelefonBuch mit separiertem bzw. ganz ohne AreaCode zu erhalten.
|
||||
|
||||
```haskell
|
||||
areaCodeFunPB :: FunPB Name Number -> FunPB Name (AreaCode,Number)
|
||||
areaCodeFunPB = fmap separateAreaCode
|
||||
|
||||
withoutAreaCodeFunPB :: FunPB Name Number -> FunPB Name Number
|
||||
withoutAreaCodeFunPB = fmap (snd.separateAreaCode)
|
||||
```
|
||||
|
||||
|
||||
|
||||
```haskell
|
||||
result = "Suche \"Paula\" in (FunPB Name Number): \n"
|
||||
++ (show $ runFunPB (dataToFunPB simpleData) "Paula") ++ "\n"
|
||||
++ "Suche \"Paula\" in (FunPB Name (AreaCode,Number)): \n"
|
||||
++ (show $ runFunPB (areaCodeFunPB $ dataToFunPB simpleData) "Paula") ++ "\n"
|
||||
++ "Suche \"Paula\" in (FunPB Name Number) ohne Vorwahl: \n"
|
||||
++ (show $ runFunPB (withoutAreaCodeFunPB $ dataToFunPB simpleData) "Paula")
|
||||
|
||||
```
|
||||
|
7
src/Aufgabe4.hs
Normal file
7
src/Aufgabe4.hs
Normal file
@ -0,0 +1,7 @@
|
||||
module Aufgabe4 where
|
||||
|
||||
-- Aufgabe 4 finden Sie auf dem branch `ghc-vis`.
|
||||
-- Sie können auf diesen mit dem Befehl `git checkout ghc-vis` gelangen.
|
||||
-- Führen Sie dort zunächst das Installationsscript `install_dependencies.sh` aus.
|
||||
|
||||
result = "foo"
|
7
src/Aufgabe4.lhs
Normal file
7
src/Aufgabe4.lhs
Normal file
@ -0,0 +1,7 @@
|
||||
> module Aufgabe4 where
|
||||
|
||||
Aufgabe 4 finden Sie auf dem branch `ghc-vis`.
|
||||
Sie können auf diesen mit dem Befehl `git checkout ghc-vis` gelangen.
|
||||
Führen Sie dort zunächst das Installationsscript `install_dependencies.sh` aus.
|
||||
|
||||
> result = "foo"
|
7
src/Aufgabe4.md
Normal file
7
src/Aufgabe4.md
Normal file
@ -0,0 +1,7 @@
|
||||
> module Aufgabe4 where
|
||||
|
||||
Aufgabe 4 finden Sie auf dem branch `ghc-vis`.
|
||||
Sie können auf diesen mit dem Befehl `git checkout ghc-vis` gelangen.
|
||||
Führen Sie dort zunächst das Installationsscript `install_dependencies.sh` aus.
|
||||
|
||||
> result = "foo"
|
9
src/DataPB.hs
Normal file
9
src/DataPB.hs
Normal file
@ -0,0 +1,9 @@
|
||||
module DataPB where
|
||||
|
||||
import qualified Data.Attoparsec.Text as A
|
||||
import Data.Attoparsec.Combinator
|
||||
import qualified Data.Text as T
|
||||
|
||||
simpleData :: [(String,String)]
|
||||
simpleData = [("Phillip","(04165) 6048168"),("Michael","(0148) 56121127"),("Phillip","(03548) 4538973"),("Paula","(030) 664940"),("Paul","(088) 08933337"),("Sylvester","(035588) 582174"),("Harriet","(0751) 75825269"),("Ariane","(0302) 49046118"),("Michael","(06650) 6975458"),("Kylie","(046) 77199945"),("Lee","(032509) 210171"),("Hunter","(06929) 7068643"),("Marvin","(036623) 741589"),("Paul","(0229) 13909736"),("Linda","(0859) 15505790"),("Lydia","(039229) 379675"),("Michael","(0755) 98407141"),("Skyler","(035869) 897089"),("Ariane","(035) 22332444"),("Eden","(0080) 20592805"),("John","(09857) 4504229"),("Jenette","(0182) 34362051"),("Delilah","(035690) 139671"),("Michael","(034973) 388559"),("John","(0451) 08133630"),("Madonna","(03897) 0007997"),("Madeline","(0600) 19801141"),("Francesca","(087) 58002539"),("Latifah","(04010) 3533294"),("Lucas","(08963) 4253453"),("Acton","(034060) 453837"),("Shelby","(039459) 871551"),("Keiko","(047) 07336335"),("Moses","(017) 73610349"),("Samantha","(034114) 317044"),("Logan","(00017) 2404967"),("Marcia","(041) 04583123"),("Allistair","(0707) 04978234"),("Hedwig","(037227) 674138"),("Phillip","(01175) 6633514"),("Paul","(084) 47394790"),("Paula","(0243) 06440875"),("Michael","(065) 98178780"),("Paul","(00622) 0087233"),("Stacy","(004) 38785128"),("Stephen","(043) 84694380"),("Michael","(053) 55705629"),("Christine","(001) 44243108"),("Paul","(030513) 239204"),("Phillip","(07043) 5061835"),("Paula","(036638) 3341652")]
|
||||
|
21
src/FunPB.hs
Normal file
21
src/FunPB.hs
Normal file
@ -0,0 +1,21 @@
|
||||
module FunPB where
|
||||
|
||||
import Control.Monad
|
||||
|
||||
data FunPB a b = FunPB { runFunPB :: a -> (a,[b]) }
|
||||
|
||||
instance Monoid (FunPB a b) where
|
||||
mempty = FunPB $ \k -> (k,mempty)
|
||||
mappend pb1 pb2 = FunPB $ \n -> (,) n $ msum . (<$>) (uncurry (flip const).((flip runFunPB) n)) $ [pb1,pb2]
|
||||
|
||||
addAssoc :: Eq a => (a,b) -> FunPB a b -> FunPB a b
|
||||
addAssoc (n,nr) pb = FunPB $ \n' -> if n' == n then ((:) nr) <$> runFunPB pb n' else runFunPB pb n'
|
||||
|
||||
delAssoc :: Eq a => a -> FunPB a b -> FunPB a b
|
||||
delAssoc n pb = FunPB $ \n' -> if n == n' then runFunPB mempty n' else runFunPB pb n'
|
||||
|
||||
multiFind :: [FunPB a b] -> a -> (a,[b])
|
||||
multiFind = runFunPB.mconcat
|
||||
|
||||
dataToFunPB :: Eq a => [(a,b)] -> FunPB a b
|
||||
dataToFunPB = mconcat.fmap ((flip addAssoc) mempty)
|
6
src/Lib.hs
Normal file
6
src/Lib.hs
Normal file
@ -0,0 +1,6 @@
|
||||
module Lib
|
||||
( someFunc
|
||||
) where
|
||||
|
||||
someFunc :: IO ()
|
||||
someFunc = putStrLn "someFunc"
|
5
stack.yaml
Normal file
5
stack.yaml
Normal file
@ -0,0 +1,5 @@
|
||||
extra-package-dbs: []
|
||||
packages:
|
||||
- '.'
|
||||
extra-deps: []
|
||||
resolver: lts-8.9
|
66
test/Aufgabe1-Spec.hs
Normal file
66
test/Aufgabe1-Spec.hs
Normal file
@ -0,0 +1,66 @@
|
||||
import Aufgabe1
|
||||
|
||||
import Test.Framework.Providers.HUnit (testCase)
|
||||
import Test.Framework.Runners.Console (defaultMain)
|
||||
import Test.HUnit
|
||||
|
||||
|
||||
{- TEST DATA -}
|
||||
|
||||
data1,data2,data3 :: [(String,String)]
|
||||
data1 = [("Phillip","(04165) 9876543"),("Phillip","(03548) 1234567"),("Paula","(035383) 567890")]
|
||||
data2 = [("Paula","(04165) 8765432"),("Michael","(03548) 2345678"),("Ariane","(035383) 678901")]
|
||||
data3 = [("Paula","(04165) 7654321"),("Hannelore","(03548) 3456789"),("Helmut","(035383) 789012")]
|
||||
|
||||
noData :: [(String,String)]
|
||||
noData = mempty
|
||||
|
||||
xPB :: PhoneBook
|
||||
xPB = PB $ \n -> [b|(a,b)<-data1, n==a]
|
||||
|
||||
yPB :: PhoneBook
|
||||
yPB = PB $ \n -> [b|(a,b)<-data2, n==a]
|
||||
|
||||
zPB :: PhoneBook
|
||||
zPB = PB $ \n -> [b|(a,b)<-data3, n==a]
|
||||
|
||||
examplePB = xPB
|
||||
|
||||
emptyPhoneBook :: PhoneBook
|
||||
emptyPhoneBook = PB $ \a -> [b|(a,b)<-noData]
|
||||
|
||||
{- TEST CASES -}
|
||||
|
||||
usePBTest = testCase "Benutze beispielhaftes PhoneBook"
|
||||
$ assertEqual "usePB examplePB \"Phillip\" sollte folgende zwei Nummern rausgeben" ["(04165) 9876543","(03548) 1234567"]
|
||||
$ usePB examplePB "Phillip"
|
||||
|
||||
mappendTest = testCase "Assoziativität von mappend"
|
||||
$ assertEqual "Assoziativität von mappend ist nicht erfüllt" (usePB (mappend (mappend xPB yPB) zPB) "Paula")
|
||||
$ usePB (mappend xPB $ mappend yPB zPB) "Paula"
|
||||
|
||||
memptyTest1 = testCase "Linksidentität von mempty"
|
||||
$ assertEqual "Linksidentität von mempty ist nicht erfüllt" (usePB xPB "Phillip")
|
||||
$ usePB (mappend xPB mempty) "Phillip"
|
||||
|
||||
memptyTest2 = testCase "Rechtsidentität von mempty"
|
||||
$ assertEqual "Rechtsidentität von mempty ist nicht erfüllt" (usePB xPB "Phillip")
|
||||
$ usePB (mappend mempty xPB) "Phillip"
|
||||
|
||||
addEntryTest = testCase "Füge Name-Nummer-Verknüpfung hinzu"
|
||||
$ assertEqual "Die hinzugefügte Nummer wird nicht gefunden" ["12345"]
|
||||
$ usePB (addEntry "NeuerName" "12345" emptyPhoneBook) "NeuerName"
|
||||
|
||||
delEntryTest = testCase "Lösche Name-Nummer-Verknüpfung"
|
||||
$ assertEqual "Die gelöschte Nummer wird weiterhin gefunden" []
|
||||
$ usePB (delEntry "Paula" xPB) "Paula"
|
||||
|
||||
findInMultTest = testCase "Suche in mehreren PhoneBooks"
|
||||
$ assertEqual "Es werden nicht alle drei Nummern von Paula gefunden" ["(035383) 567890","(04165) 8765432","(04165) 7654321"]
|
||||
$ findInMult [xPB,yPB,zPB] "Paula"
|
||||
|
||||
|
||||
tests = [usePBTest,mappendTest,memptyTest1,memptyTest2,addEntryTest,delEntryTest,findInMultTest]
|
||||
|
||||
main :: IO ()
|
||||
main = defaultMain tests
|
7
test/Aufgabe2-Spec.hs
Normal file
7
test/Aufgabe2-Spec.hs
Normal file
@ -0,0 +1,7 @@
|
||||
main :: IO ()
|
||||
main = putStrLn $ "Eine Testung von Aufgabe 2 mit HUnit ist nicht sinnvoll. \n"
|
||||
++ "Falls Sie feststecken und nicht weiterkommen: \n"
|
||||
++ "Welche Typklassen kennen Sie? \n"
|
||||
++ "Wie sehen deren Instanzen für die vorliegenden Datentypen aus? \n"
|
||||
++ "Welche Regeln/Gesetze implizieren diese Typklassen? \n"
|
||||
++ "Eventuell lassen sich Ausdrücke mehrfach verallgemeinern. \n"
|
77
test/Aufgabe3-Spec.hs
Normal file
77
test/Aufgabe3-Spec.hs
Normal file
@ -0,0 +1,77 @@
|
||||
import Aufgabe3
|
||||
import DataPB
|
||||
import FunPB
|
||||
import AreaCode
|
||||
|
||||
import Test.Framework.Providers.HUnit (testCase)
|
||||
import Test.Framework.Runners.Console (defaultMain)
|
||||
import Test.HUnit
|
||||
|
||||
|
||||
{- TEST DATA -}
|
||||
|
||||
funPBTest = dataToFunPB simpleData
|
||||
|
||||
vielleichtValues = [(Etwas 1234),Nichts]
|
||||
|
||||
entwederValues :: [Entweder String [[[Integer]]]]
|
||||
entwederValues = [(Jenes "just a string"),(Dieses [[[12344321]]])]
|
||||
|
||||
konstantValue = Konstant True
|
||||
|
||||
f = const 1
|
||||
g = const '0'
|
||||
|
||||
|
||||
{- TEST CASES-}
|
||||
|
||||
atleast5CharFalse = testCase "Teste Randbedingung (==False) für atleast5Char"
|
||||
$ assertEqual "Der Ausdruck >>> runPred atLeast5Char $ \"1234\" \nsollte zu False auswerten" False
|
||||
$ runPred atLeast5Char $ "1234"
|
||||
|
||||
atleast5CharTrue = testCase "Teste Randbedingung (==True) für atleast5Char"
|
||||
$ assertEqual "Der Ausdruck >>> runPred atLeast5Char $ \"12345\" \nsollte zu True auswerten" True
|
||||
$ runPred atLeast5Char $ "12345"
|
||||
|
||||
|
||||
|
||||
fmapVielleichtTestIdentity = testCase "Functor Vielleicht: Strukturerhaltung"
|
||||
$ assertEqual "Es sollte gelten: fmap id == id . " (id <$> vielleichtValues)
|
||||
$ ((fmap id) <$> vielleichtValues)
|
||||
|
||||
fmapVielleichtTestComposability = testCase "Functor Vielleicht: Komponierbarkeit"
|
||||
$ assertEqual "Es sollte gelten: fmap f . fmap g == fmap (f . g) . " ((fmap f . fmap g) <$> vielleichtValues)
|
||||
$ ((fmap (f . g)) <$> vielleichtValues)
|
||||
|
||||
|
||||
fmapEntwederTestIdentity = testCase "Functor (Entweder a): Strukturerhaltung"
|
||||
$ assertEqual "Es sollte gelten: fmap id == id . " (id <$> entwederValues)
|
||||
$ ((fmap id) <$> entwederValues)
|
||||
|
||||
fmapEntwederTestComposability = testCase "Functor (Entweder a): Komponierbarkeit"
|
||||
$ assertEqual "Es sollte gelten: fmap f . fmap g == fmap (f . g) . " ((fmap f . fmap g) <$> entwederValues)
|
||||
$ ((fmap (f . g)) <$> entwederValues)
|
||||
|
||||
|
||||
fmapKonstantTestIdentity = testCase "Functor (Konstant a): Strukturerhaltung"
|
||||
$ assertEqual "Es sollte gelten: fmap id == id . " (id konstantValue)
|
||||
$ ((fmap id) konstantValue)
|
||||
|
||||
fmapKonstantTestComposability = testCase "Functor (Konstant a): Komponierbarkeit"
|
||||
$ assertEqual "Es sollte gelten: fmap f . fmap g == fmap (f . g) . " ((fmap f . fmap g) konstantValue)
|
||||
$ ((fmap (f . g)) konstantValue)
|
||||
|
||||
|
||||
|
||||
fmapFunPBTestIdentity = testCase "Functor (FunPB a): Strukturerhaltung"
|
||||
$ assertEqual "Es sollte gelten: fmap id == id . " (runFunPB (id funPBTest) "Paula")
|
||||
$ (runFunPB ((fmap id) funPBTest) "Paula")
|
||||
|
||||
fmapFunPBTestComposability = testCase "Functor (FunPB a): Komponierbarkeit"
|
||||
$ assertEqual "Es sollte gelten: fmap f . fmap g == fmap (f . g) . " (runFunPB (fmap snd . fmap separateAreaCode $ funPBTest) "Paula")
|
||||
$ (runFunPB ((fmap (snd.separateAreaCode)) funPBTest) "Paula")
|
||||
|
||||
tests = [atleast5CharFalse,atleast5CharTrue,fmapVielleichtTestIdentity,fmapVielleichtTestComposability,fmapEntwederTestIdentity,fmapEntwederTestComposability,fmapKonstantTestIdentity,fmapKonstantTestComposability,fmapFunPBTestIdentity,fmapFunPBTestComposability]
|
||||
|
||||
main :: IO ()
|
||||
main = defaultMain tests
|
5
test/Aufgabe4-Spec.hs
Normal file
5
test/Aufgabe4-Spec.hs
Normal file
@ -0,0 +1,5 @@
|
||||
main :: IO ()
|
||||
main = putStrLn $ "Für Aufgabe 4 sind keine Tests vorgesehen. \n"
|
||||
++ "Zur Bearbeitung von Aufgabe 4 wechseln Sie bitte auf den branch `ghc-vis`. \n"
|
||||
++ "Dies erreichen Sie mit dem Befehl `git checkout ghc-vis`. \n"
|
||||
++ "Führen Sie dort zunächst das Installationsscript `install_dependencies.sh` aus. "
|
110
zettel2.cabal
Normal file
110
zettel2.cabal
Normal file
@ -0,0 +1,110 @@
|
||||
name: zettel2
|
||||
version: 0.1.0.0
|
||||
synopsis: Second Assignment of FFPiHaskell 2017
|
||||
-- description:
|
||||
homepage: https://github.com/FFPiHaskell/zettel2-skeleton#readme
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
author: FFPiHaskell Tutors
|
||||
maintainer: sdressel@techfak.uni-bielefeld.de
|
||||
copyright: 2017 FFPiHaskell Tutors
|
||||
category: cli
|
||||
build-type: Simple
|
||||
extra-source-files: README.md
|
||||
cabal-version: >=1.10
|
||||
|
||||
|
||||
-- library for all things common in all exercises/not neccessary for students
|
||||
-- to solve assignments
|
||||
library
|
||||
hs-source-dirs: src
|
||||
exposed-modules: Lib
|
||||
, DataPB
|
||||
, AreaCode
|
||||
, FunPB
|
||||
, Aufgabe1
|
||||
, Aufgabe2
|
||||
, Aufgabe3
|
||||
, Aufgabe4
|
||||
build-depends: base >= 4.7 && < 5
|
||||
, attoparsec
|
||||
, text
|
||||
default-language: Haskell2010
|
||||
|
||||
executable aufgabe1
|
||||
hs-source-dirs: app
|
||||
main-is: Aufgabe1Main.hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends: base
|
||||
, zettel2
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite aufgabe1-tests
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: test
|
||||
main-is: Aufgabe1-Spec.hs
|
||||
build-depends: base
|
||||
, zettel2
|
||||
, test-framework
|
||||
, test-framework-hunit
|
||||
, HUnit
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
default-language: Haskell2010
|
||||
|
||||
executable aufgabe2
|
||||
hs-source-dirs: app
|
||||
main-is: Aufgabe2Main.hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends: base
|
||||
, zettel2
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite aufgabe2-tests
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: test
|
||||
main-is: Aufgabe2-Spec.hs
|
||||
build-depends: base
|
||||
, zettel2
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
default-language: Haskell2010
|
||||
|
||||
executable aufgabe3
|
||||
hs-source-dirs: app
|
||||
main-is: Aufgabe3Main.hs
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
build-depends: base
|
||||
, zettel2
|
||||
default-language: Haskell2010
|
||||
|
||||
test-suite aufgabe3-tests
|
||||
type: exitcode-stdio-1.0
|
||||
hs-source-dirs: test
|
||||
main-is: Aufgabe3-Spec.hs
|
||||
build-depends: base
|
||||
, zettel2
|
||||
, test-framework
|
||||
, test-framework-hunit
|
||||
, HUnit
|
||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
||||
default-language: Haskell2010
|
||||
|
||||
executable aufgabe4
|
||||
hs-source-dirs: app
|
||||
main-is: Aufgabe4Main.hs
|
||||
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
|
||||
default-language: Haskell2010
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
location: https://github.com/FFPiHaskell/zettel2-skeleton
|
Loading…
Reference in New Issue
Block a user