Classical Themes of Computer Science UE WS 2017/18 Aufgabenblatt Thema: Functional Programming Dr. Bernhard Aichernig Andrea Pferscher TU Graz, Institut für Softwaretechnologie Ausgabe: 29.11.2017 Fragestunde: 13.12.2017, 18:00 Uhr Abgabe: bis 15.12.2017, 23:59 Uhr per SVN Abgabegespräche: 11.01. und 12.01.2018, 10:00 18:00 Uhr, IST Besprechungsraum Modus Gruppen: bisherige 5er Gruppen sind beizubehalten Abgabegespräche: Die Gruppen werden zu Abgabegesprächen eingeladen. Alle Teilnehmer einer Gruppe müssen erscheinen. Bei Krankheit bedarf es einer ärztlichen Bestätigung. Das Datum wurde zu Beginn der LV mitgeteilt (siehe Einführungsfolien). Dauer: 15 30 Min. Abgabe Abgabedatei: Auf der Homepage finden Sie ein Scala-File. Dieses File enthält Funktionen die auszuprogrammieren sind. Beweise: Beweise sind als Kommentare in das Abgabe-File zu schreiben. Bonus: Mit * gekennzeichnete Beispiele sind Bonus. Sie können damit eventuelle Abzüge aus anderen Beispielen kompensieren. Sie können auf das gesamte Blatt jedoch nicht mehr als 100 Punkte erreichen. Header: Auch andere organisatorische Daten müssen im Header ergänzt werden. Dateiname: Der Name des Files lautet ktdcw-fp-<gruppennummer>.scala. Verwenden Sie die Ihnen von dem Online-System zugeteilt wurde. Ordnerstruktur: Das SVN Repository muss folgende Struktur aufweisen: <Repository-URL>/aichernig/ktdcw-FP-<Gruppennummer>.scala Abgabegespräche: Die Gruppen werden zu Abgabegesprächen eingeladen. Alle Teilnehmer einer Gruppe müssen erscheinen. Bei Krankheit bedarf es einer ärztlichen Bestätigung. Das Datum wurde zu Beginn der LV mitgeteilt (siehe Einführungsfolien). Dauer: 15 30 Min. 1
Aufgabenstellung Achtung: Alle Definitionen müssen so wie in der Vorlesung applikativ (funktional) sein (also keine Variablendeklarationen mit var). 1 Rekursive Funktionen (20P) 1. Tail recursion: Es ist eine Funktion rms(l) = m tail-rekursiv zu definieren, die eine Liste von ganzen Zahlen l übernimmt und das quadratische Mittel 1 m als reelle Zahl zurückliefert, z.b. rms(list(1, 2, 3, 4)) = 2.7386127875258306 Zur Berechnung des rms dürfen die Library-Funktionen scala.math.pow(a,b) und scala.math.sqrt(a) verwendet werden. Bei einer leeren Liste oder wenn das einzige Element 0 ist, soll 0.0 retourniert werden. (2 Punkte) 2. Tail recursion: Gegeben sei folgende Funktion: 1 def prod(as: List[Int]): Int = as match { 2 case Nil => 1 3 case x::xs => x prod(xs)} Definieren Sie eine tail-rekursive Version prod2 der obigen Funktion prod. (2 Punkte) 3. Generics, Currying: Definieren Sie eine generische Funktion prodg für allgemeine Listen vom Typ List[T]. Ein allgemeiner Multiplikations-Operator vom Typ (T, T ) => T und das Null-Element für den Typ T sollen als weitere Parameter mit übergeben werden. Die Funktion soll curried sein! Definieren Sie auch die obige Funktion prod mit Hilfe der neuen allgemeinen Funktion prodg, nutzen Sie dazu eine Anonymefunktion. (4 Punkte) 4. Definieren Sie eine Funktion filterrange(p, s, e) = l, die eine Liste l zwischen den Zahlen s und e zurückgibt (s und e inklusive). Die Liste soll jedoch nur jene Elemente enthalten, für die p wahr ist. Implementieren Sie mit expliziter linearer Rekursion. (4 Punkte) 5. Überlegen Sie, wie die Funktion filterrange(p, s, e) in ScalaCheck getestet werden kann. Implementieren Sie mindestens zwei sinnvolle Properties. (8 Punkte) 2 Induktionsbeweise (16P) 1. Beweisen Sie, dass (8 Punkte) prod(l) = prod2(l) 1 https://en.wikipedia.org/wiki/root_mean_square 2
2. Beweisen Sie, dass (8 Punkte) member(e,append(as,bs)) = member(e,as) member(e,bs) * Beweisen Sie, dass (6 Punkte) reverse(append(as,bs)) = append(reverse(bs), reverse(as)) 3 Sortieren (14P) 1. Definieren Sie eine Funktion bubblesort(as) 2 rekursiv, welche eine Liste as von Integern nach dem BubbleSort-Verfahren sortiert. (8 Punkte) 2. Generalisieren Sie diese Funktion in eine Funktion bubblesortg für beliebige Listenelemente. (2 Punkte) 3. Schreiben Sie eine ScalaCheck-Property um zu zeigen, dass bubblesort und isort aus der Vorlesung das gleiche Verhalten zeigen. (4 Punkte) 4 Higher-Order List Functions (16P) 1. Definieren Sie prod mit mit Hilfe einer f old-funktion. (3 Punkte) 2. Definieren Sie die partition-funktion aus der Vorlesung mit Hilfe einer f old- Funktion. (3 Punkte) 3. Definieren Sie eine Funktion max zum Finden des Maximums einer nichtleeren Liste von Integern mittels einer f old-funktion. (2 Punkte) 4. Definieren Sie die isort-funktion aus der Vorlesung mit Hilfe einer f old-funktion. Es soll auch die insert-funktion mit f old implementiert werden (4 Punkte) 5. Definieren Sie eine generische Funktion concatm ap, die eine Funktion f vom Typ A => List[B] und eine List von Typ List[A] als Parameter enthält. Die Funktion f soll auf jedes Element angewandt werden. Die so entstehende Liste von Listen soll wieder in eine Liste verflacht werden. Nutzen Sie zur Implementierung fold, map und compose. (4 Punkte) 5 Case Classes (14P) 1. Erweitern Sie die Boolean Expressions BExp aus der Vorlesung um ein NAnd und eine Implication. (2 Punkte) 2 https://en.wikipedia.org/wiki/bubble_sort 3
2. Erweitern Sie die Funktion simplify(b) aus der Vorlesung entsprechend der erweiterten Expressions. (2 Punkte) 3. Definieren Sie folgende rekursive Datenstruktur mittels Case Classes: Ein Binärbaum vom Typ BT ree ist entweder ein Blatt Leaf(e), mit einem Element e oder ein Knoten N ode(t1, t2). Ein Knoten soll einen linken Teilbaum t1, einen rechten Teilbaum t2 beinhalten. Der Binärbaum soll wie Listen generisch sein. (2 Punkte) 4. Schreiben Sie eine Funktion treemap die eine Funktion f auf jedes Element des Binärbaumes anwendet. Die Funktion soll curried sein. (4 Punkte) 5. Schreiben Sie eine Funktion treet olist die einen Binärbaum in eine Liste verflacht. (4 Punkte) * Schreiben Sie eine treef old Funktion und nutzten Sie diese um treet olist zu implementieren. (4 Punkte) * Schreiben eine ScalaCheck Property und einen Generator für BTree um zu zeigen das gilt treet olist compose treem ap(f)(t) = treet olist(t).map(f) wobei f = x => x + 1 (8 Punkte) 6 Actors (20P) Realisieren Sie ein Netzwerk, welches dazu dient Nachrichten eines Masters im Netzwerk innerhalb der Clients zu verbreiten. Jeder Master hat n Clients, welche in einem Ring angeordnet sind. Somit besitzt jeder Client zwei Nachbar-Clients. Zur eindeutigen Identifikation des Clients besitzt dieser eine eindeutige id, welche zwischen 0 und n 1 vergeben werden soll. Der Master sendet einem Client eine Distribute-Nachricht, bestehend aus Text und Richtung der Nachricht. Es soll nun möglich sein, diese Nachricht von einem Client zum nächsten Client zu senden, dabei gibt der Master die Richtung der Nachricht vor. Die Richtung bestimmt, ob die Nachricht immer an den nächsten Client (id + 1) oder den vorherigen Client (id 1) gesendet werden soll. Sobald jener Client, der die Nachricht ursprünglich vom Master empfangen hat, die selbe Nachricht wieder empfängt, sendet dieser Client an den Master eine F inish-nachricht. Damit soll die Nachricht einmal im Kreis versendet werden. Zur eindeutigen Identifikation der Nachricht enthält diese eine id. Bekommt der Master ein Stop-Signal, beendet er voher alle seine Clients und danach sich selbst. Bekommt ein Client eine Stop-Nachricht, leitet er dieses an alle seine Nachbarn weiter und beendet sich anschließend. Der Master wird jedoch von keinem Client gestoppt. 4
Figure 1: Nachdem der Master die Distribute-Nachricht versendet hat, folgt die Nachricht entweder den blauen oder den orangen Pfeilen. Sobald die Nachricht wieder bei dem Client, der die Nachricht vom Master erhalten hat, angekommen ist, sendet der Client eine F inish-nachricht an den Master. Testen Sie die Implementierung auch mit einer großen Anzahl an Aktoren und gleichzeitigen Nachrichten. * (8 Punkte) Implementieren Sie eine Fehlerstrategie für den Master, sodass eine Nachricht, die im Ring-Netzwerk verloren ging, nochmals gesendet wird. Je nach Komplexität der Implementierung können bis zu acht Punkte erreicht werden. 5