WS 13/14 Zusatzblatt zur - Softwaretechnik und Programmiersprachen

Werbung
Lehrstuhl für Softwaretechnik und Programmiersprachen
Jens Bendisposto
Funktionale Programmierung – WS 13/14
Zusatzblatt zur Klausurvorbereitung
Achtung: Dieses Blatt ist keine Probeklausur. Es ist keinesfalls eine angemessene Vorbereitung
nur die Aufgaben dieses Blattes zu lösen. Die Aufgaben sind in zufälliger Reihenfolge. Die
Musterlösung werde ich am kommenden Freitag (14.2.2012) veröffentlichen.
Aufgabe 9.1 (Punktevergabe)
In einer Klausur soll eine Multiple Choice Aufgabe bewertet werden. Zu jeder Frage gibt es zwei
Antwortmöglichkeiten. Für das Bewertungsschema sollen folgende Eigenschaften gelten:
1. Ein Student der ausschliesslich rät, soll im Mittel 0 Punkte bekommen
2. Es sollen keine negativen Punkte vergeben werden
3. Maximal sollen k Punkte vergeben werden
Sei k die Anzahl der maximalen Punkte und x die Anzahl der richtig angekreuzten Lösungen
Folgendes Schema erfüllt die Bedingungen:
(
0
x ≤ k2
p=
2(x − k2 ) sonst
a) Implementieren Sie eine Funktion (defn punkte [x k] ...), die die Punkte ausrechnet.
b) Überprüfen Sie, dass die Eigenschaften gelten.
c) Angenommen ein Student kennt die Antwort auf eine Frage nicht. Kann sich der Student
durch Raten verschlechtern?
Aufgabe 9.2 (Datenstrukturen)
Die Banker’s Queue ist eine funktionale Datenstruktur, die in der Praxis gut funktioniert. Die
Datenstruktur besteht aus zwei Listen. Aus einer Liste (front) werden Elemente herausgeholt,
in die andere (rear) werden Elemente abgelegt. Wenn die rear Liste länger ist als die Front-Liste
wird die rear Liste umgedreht, an die front Liste angehangen und geleert.
a) Implementieren Sie die Banker’s Queue mit Hilfe eines Records und eines Protocols. Das
Protokoll soll 2 Funktionen push und take spezifizieren.
b) push bekommt als Parameter die Queue und ein Element, das eingefügt wird. Zurückgegeben
wird eine Queue
c) take bekommt als Parameter die Queue. Zurückgegeben wird eine Queue, das entfernte Element wird geprintet.
d) In welcher Reihenfolge müssen die Argumente von push sein? Warum? Was könnte man tun,
wenn man die Reihenfolge umdrehen will?
Aufgabe 9.3 (Macros und Funktionen)
Gegeben seine folgende Implementierungen des logischen Operators or. Geben Sie einen Aufuf
an, bei dem sich das Verhalten der beiden Implementierung voneinander unterscheidet und
erklären Sie, warum sich die Implementierungen unterscheiden.
(defmacro or-m
([] nil)
([x] x)
([x & more]
`(let [or# ~x]
(if or# or# (or-m ~@more)))))
(defn or-fn
([] nil)
([x] x)
([x & more]
(if x x (apply or-fn more))))
Aufgabe 9.4 (Lazyness)
Angenommen Clojure hätte keine Funktion iterate. Implementieren Sie eine Funktion, die eine
pure Funktion f und einen Startwert x bekommt und eine unendliche Sequenz mit den Werten
x, (f x), (f (f x)), (f (f (f x))), ... zurückgibt.
Aufgabe 9.5 (Higher Order Funktionen)
Beim Kartenspiel Black-Jack ist es das Ziel eines Spielers mit seinen Karten möglichst nahe
an den Wert 21 zu kommen. Asse werden als 1 oder 11 gezählt. Andere Bildkarten haben eine
Wert von 10. Die Karten 2-10 haben den aufgedruckten Wert. Ein Spieler, der einen Wert
erzielt, der grösser ist als 21 hat automatisch verloren. Die niedrigen Karten 2-10 werden durch
die entsprechenden nummerischen Werte repräsentiert. Bildkarten werden durch :bube, :dame,
:koenig aund :ass repräsentiert.
a) Implementieren Sie eine Clojure Funktion, die aus einer gegebenen Kartensequenz die optimale Kartensumme berechnet.
=> (opt-val [2 5 7])
14
=> (opt-val [10 :ass])
21
=> (opt-val [10 9 :ass])
20
b) Schreiben Sie eine Funktion, die eine Sequenz von Kartensequenzen bekommt und den oder
die Sieger berechnet. Ausgabe ist eine Sequenz der Siegersequenzen.
Aufgabe 9.6 (Fixpunkt)
Die Eulersche Zahl e kann mit Hilfe folgender Summe ausgerechnet werden.
e=
∞
X
1
1 1
1
=1+1+ + +
+ ···
k!
2 6 24
k=0
Schreiben Sie eine Clojure Funktion, die e mit einer Genauigkeit von 10−3 berechnet. Geben Sie
alle benötigten Hilfsfunktionen an.
Aufgabe 9.7 (Multimethoden)
Aus einer Legacy Anwendung sollen Daten importiert werden. Es handelt sich dabei um Koordinaten. Das Problem ist, das zwei und dreidimensionale Koordinaten gemischt in einem Bytestrom
gesendet werden. Unsere Anwendung erhält die Daten als einen einzigen String. Die einzelnen
Zahlen sind durch Leerzeichen voneinander getrennt, die Koordinaten durch Zeilenumbrüche.
Ein Beispiel-Datenstrom könnte so aussehen:
(def input "23 8 15\n11 0\n0 5\n-10 15 9")
user=> (map identity input)
(\2 \3 \space \8 \space \1 \5 \newline \1 \1 \space \0 \newline \0 \space \5
\newline \- \1 \0 \space \1 \5 \space \9)
a) Implementieren Sie eine Funktion, die aus dem String eine Sequenz von Sequenzen generiert,
in der die Koordinaten voneinander getrennt sind. Im Beispiel sollte es so funktionieren. Sie
können davon ausgehen, dass Sie read-string sicher verwenden können.
user=> (as-seq input)
([23 8 15] [11 0] [0 5] [-10 15 9])
;; Auch ok:
;; ((23 8 15) (11 0) (0 5) (-10 15 9))
;; [[23 8 15] [11 0] [0 5] [-10 15 9]]
b) In Clojure wollen wir die Daten in Records speichern. Dazu sind folgende beiden Vektoren
definiert:
(defrecord Vec2d [x y])
(defrecord Vec3d [x y z])
Implementieren Sie eine Multimethod, die folgendermassen funktioniert:
user=> (map as-vector (as-seq input))
(#user.Vec3d{:x 23, :y 8, :z 15}
#user.Vec2d{:x 11, :y 0}
#user.Vec2d{:x 0, :y 5}
#user.Vec3d{:x -10, :y 15, :z 9})
c) Kann man das Problem auch mit Protokollen sinnvoll lösen? Falls ja: Geben Sie eine Implementierung an. Falls nein: Erklären Sie warum es nicht gut geht.
Aufgabe 9.8 (Monaden)
Beim Fizzbuzz Problem sollen in einer Sequenz von Zahlen alle durch 3 teilbaren Zahlen durch
:fizz, alle durch 5 teilbaren Zahlen durch :buzz und alle durch 3 und 5 teilbaren Zahlen durch
:fizzbuzz ersetzt werden.
Im Folgenden werden wir eine Variante des Problems betrachten. Statt :fizzbuzz soll nichtdeterministisch entweder :fizz oder :buzz eingesetzt werden.
a) Schreiben Sie eine Funktion fizzbuzz-mfn für die Sequenz-Monade, die für eine gegebene
Zahl die nichtdeterministische Berechnung durchführt.
b) Schreiben Sie eine Funktion fizzbuzz-m, die eine Sequenz von Zahlen bekommt und die
nichtdeterministische Funktion für die Sequenz durchführt. Ergebnis sollen alle möglichen
Sequenzen sein, die beim Ausführen der Berechnung auftreten können.
Hinweis: Die monadische map Funktion m-map könnte helfen.
Beispielaufruf:
=> (fizzbuzz-m [1 2
((1 2 :fizz 4 :buzz
(1 2 :fizz 4 :buzz
(1 2 :fizz 4 :buzz
(1 2 :fizz 4 :buzz
3
7
7
7
7
4 5 7
:fizz
:fizz
:buzz
:buzz
15
16
16
16
16
16 15])
:fizz)
:buzz)
:fizz)
:buzz))
Aufgabe 9.9 (Monaden)
a) Gegeben sei eine Funktion f mit dem Typ a->b. Welchen Typ hat die Funktion, wenn man
m-lift in der Sequenzmonade auf die Funktion anwendet?
b) Ist die geliftete Funktion eine monadische Funktion? Was ist eine monadische Funktion?
Aufgabe 9.10 (Haskell)
Gegeben sei folgendes Haskell Programm. Übersetzen Sie es in Clojure.
abc
abc
abc
abc
0 n =
(m+1)
(m+1)
_ _ =
n+1
0 = abc m 1
(n+1) = abc m (abc (m+1) n)
0
Hinweis: Das Programm produziert sehr schnell sehr grosse Berechnungen, die StackOverflows
erzeugen. Für n ≤ 3 müsste es aber gut funktionieren. Bei n = 3 darf m ebenfalls nicht gross
sein. etwa m < 10.
Aufgabe 9.11 (Problem)
Gegeben sei folgende Implementierung der Fakultätsfunktion. Die Implementierung hat ein Problem. Was ist das Problem und wie kann man es lösen? Sie können davon ausgehen, dass die
Funktion immer korrekt aufgerufen wird.
(defn ! [n] (if (zero? n) 1 (*' n (! (dec n))))
Herunterladen