Aufgabe 1 ========= > module Aufgabe1 where > import AdressSys Applicative style – an abstract pattern for everyday use. -------------------------- Wiederholung: ----------------------------------- (<$>) :: (a -> b) -> f a -> f b (<*>) :: f (a -> b) -> f a -> f b (=<<) :: (a -> m b) -> m a -> m b -- (=<<) == flip (>>=) ----------------------------------- Aus der Vorlesung wissen Sie bereits, dass `[]` und `Maybe` `Applicative`s 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 `ID`s aus einer Liste von Datenbanken `DB`s 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))]