uebung2017_3/src/Aufgabe1.md
2017-05-08 11:16:38 +02:00

5.1 KiB
Raw Permalink Blame History

Aufgabe 1

module Aufgabe1 where  

import AdressSys  

Applicative style an abstract pattern for everyday use.

Wiederholung:

(<$>) :: Functor f =>       (a -> b)   -> f a -> f b
(<*>) :: Applicative f => f (a -> b)   -> f a -> f b
(=<<) :: Monad m =>         (a -> m b) -> m a -> m b  -- (=<<) == flip (>>=)

Aus der Vorlesung wissen Sie bereits, dass [] und Maybe Applicatives sind und dass Applicative ermöglicht, 'Funktionen im Kontext' auf Werte im Kontext anzuwenden. Außerdem haben Sie Currying kennen gelernt. Ein praktisches Muster, das sich hieraus ableiten lässt, ist das folgende:

pure f <*> x1 <*> x2 <*> .. <*> xn 
  wobei f  :: t1 -> t2 -> .. -> tn -> t' 
        x1 :: Applicative m => m t1 
        x2 :: Applicative m => m t2 
        .
        .
        xn :: Applicative m => m tn 

pure hebt die Funktion f in den Kontext m und <*> wendet f nach und nach auf alle ihre im Kontext liegenden Argumente t1 bis tn an. Vor dem Hintergrund, dass jedes Applicative auch ein Functor ist, lässt sich das Muster noch etwas verkürzen:

pure f <*> x1 <*> x2 <*> ... <*> xn 
     f <$> x1 <*> x2 <*> ... <*> xn 

Importiert aus dem Modul AdressSys sind die folgenden Datentypen und Funktionen, die ein ein Datenbanksystem zur Verwaltung persönlicher Daten repräsentieren:

type ID = Integer
type DB = [(ID,[Datum])]

newtype Age      = Age      Integer
newtype Name     = Name     String
newtype City     = City     String
newtype Email    = Email    String
newtype Phone    = Phone    String
newtype Street   = Street   String
newtype Gender   = Gender   String
newtype Postcode = Postcode String

data Adress = Adress Name Street PostCode City deriving (Show,Eq)
data Public = Public Name (Maybe Age) (Maybe Email) deriving (Show,Eq)

data Datum  = DName     Name
            | DStreet   Street
            | DPostcode Postcode
            | DEmail    Email
            | DPhone    Phone
            | DGender   Gender
            | DCity     City
            | DAge      Age
            deriving (Show,Eq)

getName     :: [Datum] -> Maybe Name 
getStreet   :: [Datum] -> Maybe Street
getPostcode :: [Datum] -> Maybe Postcode
getEmail    :: [Datum] -> Maybe Email
getPhone    :: [Datum] -> Maybe Phone
getGender   :: [Datum] -> Maybe Gender
getAge      :: [Datum] -> Maybe Age
getCity     :: [Datum] -> Maybe City
-- suchen jeweils das erste Vorkommen aus; gehen Sie davon aus, die Datenstruktur erlaube nur einmaliges Vorkommen

getDataFromID :: ID -> DB -> Maybe [Datum]
-- sucht die zu einer ID zugehörigen Daten aus einer Datenbank aus 

db1 = [(1,[DAge (Age 99),DCity (City "Portland,Oregano"),DName (Name "Mona D."),DPostcode (Postcode "42317"),DStreet (Street "Intuition 6")]),(2,[DStreet (Street "Jahnplatz 5"),DName (Name "Alfred Plickateff"),DAge (Age 22),DEmail (Email "a.plickateff@hackage.com")]),(3,[DName (Name "Gerhard Zeh")]),(4,[])]
db2 = [(2,[DAge (Age 54),DCity (City "Bielefeld"),DName (Name "Hans Joachim Meyer"),DPostcode (Postcode "33602"),DStreet (Street "Viktoriastraße 22")]),(6,[DStreet (Street "Dönerteller 1a"),DName (Name "Hannelore Hacker"),DAge (Age 76)]),(3,[DName (Name "Lisa Lista"),DEmail (Email "lisa.lista@web.de"),DAge (Age 7)]),(5,[DName (Name "Alonzo Storch"),DStreet (Street "Antenne 2"),DCity (City "Dingenskirchen"),DPostcode (Postcode "12346")])]
-- zwei Beispieldatenbanken

Gegeben eine Liste von persönlichen Daten fassen die folgenden Funktionen getAdressM und getPublicDataM Adress- bzw. öffentliche Daten zu einem entsprechenden Wert Adress bzw. Public zusammen; falls nicht alle nötigen Informationen gefunden werden, geben sie Nothing zurück.

getAdressM :: [Datum] -> Maybe Adress  
getAdressM ds = do   
  name   <- getName     ds  
  street <- getStreet   ds  
  pcode  <- getPostcode ds  
  city   <- getCity     ds  
  return (Adress name street pcode city)  

getPublicM :: [Datum] -> Maybe Public  
getPublicM ds = getName ds >>= \name -> return (Public name (getAge ds) (getEmail ds))

Implementieren Sie nun zwei Funktionen getAdressA und getPublicDataA, die das gleiche tun, im Applicative style, d.h. indem Sie das oben beschriebene Muster verwenden.

getAdressA :: [Datum] -> Maybe Adress  
getAdressA ds = undefined  

getPublicA :: [Datum] -> Maybe Public  
getPublicA ds = undefined  

Definieren Sie abschließend eine Funktion getManyAdresses im Applicative style, die unter Verwendung von getAdressFromID :: ID -> DB -> Maybe Adress Adressen für eine ganze Liste von IDs aus einer Liste von Datenbanken DBs aussucht und ausgibt.

getAdressFromID :: ID -> DB -> Maybe Adress
getAdressFromID iD db = getDataFromID iD db >>= getAdressM

getManyAdresses :: [ID] -> [DB] -> [Maybe Adress]  
getManyAdresses iDs dbs = undefined  
result = unlines $
          ["Adressen für Nutzer 1 bis 5 (ID) aus db1 und db2: ",  
          (show $ getManyAdresses [1..5] [db1,db2]),  
          "Öffentliche Daten für ID 1 db1: ",  
          (show $ (getDataFromID 1 db1 >>= getPublicA))]