Lehrstuhl für Softwaretechnik und Programmiersprachen Jens Bendisposto Funktionale Programmierung – WS 13/14 Übungsblatt 8 Aufgabe 8.1 (Protokolle) Eine Bank benutzt Clojure um ihre Konten zu verwalten. Da es verschiedene Arten von Konten gibt (Girokonten, Tagesgeldkonten, Sparbücher, ...) soll ein Protokoll definiert werden um ein Konto abstrakt verwenden zu können. a) Scheiben Sie ein Protokoll PKonto. Das Protokoll folgende Funktionen zur Verfügung stellen (Parameter sind weggelassen. Sie ms̈sen überlegen, welche Parameter benötigt werden) • einzahlen: Um einen Betrag auf dem Konto gutzuschreiben. Einzahlungen sind immer erlaubt (auch wenn das Konto gesperrt wurde) • abheben?: Soll truthy liefern, falls es möglich ist einen spezifizierten Betrag vom Konto abzuheben • abheben: Hebt einen Betrag vom Konto ab • sperren: Sperrt das Konto • entsperren: Hebt eine bestehende Sperre auf b) Definieren Sie eine Datenstruktur für ein Girokonto, das PKonto implementiert. Girtokonten haben ein Kreditlimit, das nicht überzogen werden darf. Aufgabe 8.2 (Geldautomat) Eine Debitkarte kann benutzt werden, um von einem Girokonto einen Betrag abzuheben. Dazu muss der Benutzer einen vierstelligen PIN eingeben. Wenn der PIN dreimal falsch eingegeben wird soll das zugehörige Konto gesperrt werden. Zu einem Konto gibt es potentiell mehrere Debitkarten, die unterschiedliche PINs haben. a) Implementieren Sie eine Funktion, die eine Debitkarte für ein Girokonto registriert. Bei der Registrierung wird der PIN festgelegt und im Server der Bank gespeichert. Die Funktion gibt den PIN zurück. b) An einem Geldautomaten gibt der Kunde seine Debitkarte ein und legitimiert sich für weitere Transaktionen. Das ist anders als an einem tatsächlichen Automaten, bei uns muss der Kunde am Anfang einmal die PIN eingeben und kann dann beliebig viele Aktionen durchführen. Implementieren Sie eine Funktion, die die Validierung eines Kunden durchführt. c) Implementieren Sie eine Barabhebung Aufgabe 8.3 (Software Transactional Memory) Gegeben sei folgende Funktion, die Transaktionen zwischen zwei Konten implementieren soll. (defn transfer-money (when (<= amount (swap! k1 (fn (swap! k2 (fn [k1 k2 amount] @k1) [k] (- k amount))) [k] (+ k amount))))) Ein Beispielaufruf könnte so aussehen (def a (atom 1000)) (def b (atom 100)) user=> [@a @b] [990 110] user=> (transfer-money b a 1000) nil user=> [@a @b] [990 110] a) Die Bank hat einen sehr bösen Fehler gemacht. Schreiben Sie einen Test, der den Fehler aufdeckt. Sie können dazu auch transfer-money so modifizieren, dass der Test einfacher wird. b) Reparieren Sie das Problem. c) Schreiben Sie die Funktion so um, dass sie die Protokoll-Funktionen aus den vorhergehenden Aufgaben benutzt. d) Erweitern Sie die transfer-money Funktion um Logging. Es soll mit println jede Transaktion ausgedruckt werden. Achten Sie darauf, dass das log lesbar ist. Aufgabe 8.4 Gegeben sei die Funktion my-read aus der Vorlesung vom 19.12.2013. Was gibt die Funktion für folgende Eingaben aus und warum? (my-read (my-read (my-read (my-read (my-read "'(1 2)") "`(1 2)") "`~(+ 2 7)") "`a#") "`(+ ~@[1 2 3])") Aufgabe 8.5 (Maybe) Beweisen Sie, dass Maybe ein Monoid ist. Verwenden Sie dafür folgende Definition: instance Monoid a => Monoid (Maybe a) where mempty = Nothing Nothing `mappend` m = m m `mappend` Nothing = m Just m1 `mappend` Just m2 = Just (m1 `mappend` m2) Aufgabe 8.6 (Either) Es gibt in Haskell eine Datenstruktur mit dem Namen Either, die so definiert ist: data Either a b = Left a | Right b a) Welche Typen haben folgende Ausdrücke? Left "foo" Right 1 b) Either hat bezüglich der Typvariablen eine interessante Eigenart. Welche ist das? Überlegen Sie, wie Sie zum beispiel einen Ausdruck mit dem Typ Either Integer Integer erzeugen könnten. c) Können Sie sich vorstellen, wozu man Either benutzt? Vergleichen Sie Either mit Maybe.