Christian-Albrechts-Universität zu Kiel Institut für Informatik Lehrstuhl für Programmiersprachen und Übersetzerkonstruktion Prof. Dr. Michael Hanus, Sandra Dylus, Björn Peemöller 1. Klausur zur Vorlesung „Fortgeschrittene Programmierung“ SS 15 Hinweis: Sie können Statistiken zur Klausur einsehen. Diese Klausur besteht aus 6 Aufgaben auf 5 doppelseitig bedruckten Blättern. Gesamtpunktzahl: 65 Punkte, Punktzahl zum Bestehen: 32 Punkte. Einlesezeit: 15 Minuten, Bearbeitungszeit: 120 Minuten. Bitte schreiben Sie auf jedes Blatt, das Sie abgeben, Ihren Namen und Ihre Matrikelnummer! Alle Aufgaben können unabhängig voneinander bearbeitet werden, insbesondere auch einzelne Aufgabenteile. Hierbei können Definitionen aus vorherigen Aufgabenteilen verwendet werden, auch wenn diese nicht gelöst wurden. Aus der Vorlesung bekannte Konstrukte (Prelude von Haskell, Prolog-Prädikate) dürfen verwendet werden. Hinweis: Die Einsichtnahme in die korrigierten Klausuren findet voraussichtlich am 26.08.2015 (Mittwoch), gestaffelt von 11:00 bis 11:30 Uhr (Nachnamen A-J) und von 11:30 bis 12:00 Uhr (K-Z) im CAP4 (Hochhaus) Raum 715, statt. Bitte bringen Sie dazu einen Lichtbildausweis mit. Viel Erfolg! 1 Aufgabe 1 - FortProg ist: [ ] objekt-orientiert; [ ] funktional; [ ] logisch; [ ] manchmal nicht auszuhalten 15 Punkte Es könnte/n alle, mehrere, eine oder gar keine Antwort richtig sein. Schreiben Sie die jeweiligs richtigen Antworten und ggf. zusätzliche Angaben zu jeder Frage auf; sollte keine der Antwortmöglichkeiten zutreffen, formulieren Sie dies bitte explizit. Markierungen auf dem Aufgabenzettel werden nicht berücksichtigt! Java 1. Welche der folgenden Generic-Konstrukte beschreiben Bounded Wildcards? a) b) c) d) e) <? <C <? <A <? extends B> super ?> instance A> extends ?> super A> 2. Threads in Java - welches der Programme ist valide (Hinweis: es handelt sich dabei in keinem Fall um Syntaxfehler)? a) public class MyThread implements Runnable { @Override public void run() { } public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); myThread.start(); } } b) public class MyThread implements Runnable { @Override public void run() { } public static void main(String[] args) throws InterruptedException { MyThread myThread = new Thread(new MyThread()); myThread.start(); } } c) public class MyThread extends Thread { @Override public void run() { } public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); myThread.start(); } } d) public class MyThread extends Thread { @Override public void run() { } public static void main(String[] args) throws InterruptedException { MyThread myThread = new Thread(new MyThread()); 2 myThread.start(); } } 3. Welcher Thread wacht beim Aufruf von notify() auf? a) b) c) d) e) Es wacht immer der zuletzt schlafengelegte Thread auf. Mittels der Übergabe der Thread-ID kann ein bestimmter Thread geweckt werden. Es wachen alle Threads auf und bewerben sich neu um das Lock. Es wacht immer der zuerst schlafengelegte Thread auf. Es wird ein beliebiger der systemweiten schlafenden Threads geweckt. 4. Welche der Aussagen bzgl. reentrent und Synchronisationsverfahren sind wahr? a) b) c) d) e) Eingebaute Locks (synchronized-Blöcke) sind reentrent. Semaphoren sind reentrent. Threads sind bereits reentrent. Binäre Semaphoren sind reentrent, andere Semaphoren sind es jedoch nicht. Eingebaute Locks sind nur auf this reentrent. 5. Welche der Aussagen gelten für RMI in Java bei verteilten Methodenaufrufen? a) b) c) d) e) Bei Remote-Objekten wird nur eine Referenz des Objektes übertragen. Serializable-Objekte werden in Bytes umgewandelt. Primitive Werte werden nicht kopiert. Die Parameter und der Rückgabewert müssen nicht in Bytes umgewandelt werden. Die Netzwerkkommunikation über TCP/IP ist für den Anwendungsprogrammierer sichtbar. Prolog 5. Welche der folgenden Zeichenfolgen sind syntaktisch korrekte Objekte in Prolog? Geben Sie für jede der Antwortmöglichkeiten die Kategorie (Atom, Variable, Struktur) oder kein zulässiges Objekt an. a) b) c) d) e) xY ++ _x F([1,a,3]) likes(john,mary) 6. Welche der folgenden Zeichenfolge sind valide Listen in Prolog? a) b) c) d) e) [1,2 | [3]] [1 | 3] [[1] | [3]] [1, atom | []] [1,2] 7. Welche der Anfragen wird mit true beantwortet? a) b) c) d) e) ?????- 42 is 7 * 6. 1 + 7 is 1 + 7. 1 + 3 is 5 - 1. 3 * 4. 1 * 7 is 7. 8. Welche der Anfragen wird einer Variablenbindung beantwortet? Sollten Bindungen berechnet werden, notieren Sie diese hinter der jeweiligen Zeile. 3 a) b) c) d) e) ?????- X X Y Z 3 = 2, Y is 5 + is 3 + is 3 + + 7 is is 5 + X. 3 * 2. X, X = 2. Y. X. 9. Welche Aussagen über Prolog sind richtig? a) Die Auswertungsstrategie basiert auf Breitensuche. b) Prolog ist eine Obermenge der Prädikatenlogik 1. Stufe. c) σ heißt allgemeinster Unifikator, falls für alle Unifikatoren σ 0 eine Substitution φ existiert mit σ = φ · σ0 . d) Variablen werden groß geschrieben. e) Die Implementierung von Funktionen ist in Prolog in Form von Relationen möglich. Haskell 11. Der Ausdruck [("Hallo",True),("Welt",False)] hat den folgenden Typ: a) b) c) d) e) [String] [(String,Bool)] (a,Bool) [String,Bool] [(String,Bool),(String,Bool)] 12. Welcher der folgenden Ausdrücke enthält einen Typfehler: a) b) c) d) e) 1 : 2 : [3,4] [(1),(2)] ++ [()] [1,2,3] ++ 4 [[1,2]] ++ [[3,4]] 1 : 2 : 3 : 4 : [] 13. Die Berechung des Ausdrucks [(x,y) | y <- [1..3], x <- [1..2]] ergibt: a) b) c) d) e) [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3)] [(1,1),(1,2),(2,1),(2,2),(3,1),(3,2)] [(1,2),(2,1),(3,2),(1,1),(2,2),(3,1)] [(1,1),(2,1),(1,2),(2,2),(1,3),(2,3)] [(1,1),(2,1),(3,1),(1,2),(2,2),(3,2)] 14. Die Funktion twice f x = f (f x) hat den folgenden Typ: a) b) c) d) e) a -> a -> a (a -> a) -> a -> a a -> (a -> a) -> a a -> a -> (a -> a) a -> a -> a -> a 15. Bezüglich des Datentyps data Tree a b = Tip a | Branch (Tree a b) b (Tree a b) sind folgende Werte korrekt: a) Tip (Branch (Tip 2) (Tip True) (Tip 4)) b) Branch (Tip (1)) 2 (Tip ()) c) Tip (Branch (Tip 1) "Hallo" (Tip 2)) 4 d) Branch (Tip "Hallo") () (Tip "Welt")) e) Tip () Aufgabe 2 - Wie sah nochmal die richtige Lösung aus? 10 Punkte Oh nein, beim Erstellen der Musterlösung ist leider eine studentische Lösung (vom Vorjahr) anstelle der korrekten Lösung in die Zwischenablage (copy+paste sei Dank!) geraten. Bei der Aufgabe handelt sich um die verbesserte Version des Buffer1 mit Synchronisationsobjekten, die wir um zusätzliche Funktionalitäten erweitert haben. Die bereits vorgegebenen Methoden sind in dieser Abgabe gar nicht vorhanden, sondern nur die neu definierten Methoden. Bei der Korrektur wurden die folgenden Fehler gefunden: • if-Anweisung falsch! -1 • r/w vertauscht! -1 • Verwendung von wait/notify! -1 Geben Sie für jeden der drei Fehler die entsprechende Zeile, die Begründung sowie eine entsprechende Korrektur an. 1 import java.util.concurrent.TimeoutException; 2 3 4 5 6 7 8 9 /** * Single element buffer with synchronization. * * @param <E> * Type of the element */ public class ExtBuffer<E> { 10 11 12 13 // element + empty flag private E content; private boolean empty; 14 15 16 17 // synchronization objects private Object r = new Object(); private Object w = new Object(); 18 19 20 21 public ExtBuffer() { empty = true; } 22 23 24 25 26 public ExtBuffer(E content) { this.content = content; empty = false; } 27 28 29 30 31 32 33 34 35 /** * Try to put an element into the buffer; succeeds only for an empty buffer * * @param elem * Element to put into * @return true if successful */ public boolean tryPut(E elem) { 5 synchronized (w) { if (empty) { synchronized (r) { content = elem; empty = false; r.notify(); return true; } } else { return false; } } 36 37 38 39 40 41 42 43 44 45 46 47 } 48 49 /** * Swap the element in the buffer with the given element. Suspends if the * buffer is empty. * * @param elem * Element to swap with */ public E swap(E elem) throws InterruptedException { synchronized (r) { if (empty) { r.wait(); } synchronized (w) { E res = content; content = elem; w.notify(); return res; } } } 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 /** * Overwrite the element in the buffer, even if the buffer is empty * * @param elem * Element to overwrite with */ public void overwrite(E elem) { synchronized (r) { content = elem; if (empty) { synchronized (w) { empty = false; r.notify(); } } } } 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 } 6 10 Punkte Aufgabe 3 - Make it pretty! In dieser Aufgabe wollen wir uns bereits vorgegebene Haskell-Definitionen anschauen und diese verbessern bzw. in einem anderen Stil umschreiben. 1. Die zwei folgenden Funktionsdefinitionen sehen sich sehr ähnlich. Schreiben Sie beide Definitionen mit Hilfe einer Funktion höherer Ordnung um. Sie können diese Funktion höherer Ordnung entweder selbst definieren oder eine vordefinierte Funktion aus der Prelude verwenden. import Data.Char (isDigit) findEvens :: [Int] -> [Int] findEvens [] = [] findEvens (x:xs) = if even x then x : findEvens xs else findEvens xs findDigits :: String -> String findDigits [] = [] findDigits (x:xs) = if isDigit x then x : findDigits xs else findDigits xs 2. Die folgende Funktion filtert für eine gegebene Liste von Strings genau die Strings heraus, die nur aus Buchstaben bestehen. Für diese Strings wird dann eine Tabelle mit der korrespondierenden Anzahl der Buchstaben ausgegeben. import Data.Char (isAlpha) letterTable :: [String] -> IO () letterTable [] = return () letterTable (x:xs) | all isAlpha x = do putStrLn (x ++ ": " ++ show (length x) ++ " letters") letterTable xs | otherwise = letterTable xs Es ist kein guter Stil, puren Code mit IO-Aktionen zu vermischen. Daher unterteilen wir diese Funktionsdefinition in zwei Teile: in einen puren Teil und einen Teil mit IO-Aktion. Implementieren Sie im folgenden Code die noch fehlende pure Funktionalität der Originalfunktion letterTable. letterTable :: [String] -> IO () letterTable strs = putStr (alphaWords strs) -- Hier fehlt noch die entsprechende Implementierung alphaWords = undefined 3. In der Eile kann es schon mal passieren, dass man vergisst, Typsignaturen für selbstdefinierte Funktionen anzugeben. Schreiben Sie die (möglichst allgemeinen!) Typsignaturen für die jeweiligen Funktionen auf. Wenn die Funktionen noch einen sinnvollen Namen hätten, wäre die Aufgabe vemutlich noch einfacher gewesen; geben Sie den Funktionen im Anschluss noch einen sinnvollen Namen! fa [] _ = [] fa (x:xs) p = (x,p) : fa xs p 7 fb a b c d = if a then d b else d c fc x = fc x fd [] g z = z fd (x:xs) g z = g x (fd xs g z) fe x [] = False fe x (y:ys) = x == y || fe x ys 10 Punkte Aufgabe 4 - 101010 In dieser Aufgabe sollen Sie sich mit der allseits beliebten Binärzahlkodierung beschäftigen. Erinnern Sie sich noch an die definierten Funktoren in Prolog aus Übungsblatt 10 Aufgabe 3? Wenn nein, bekommen Sie bitte keine Panik, es folgt eine kleine Gedächtnisstütze. • Ein Term der Form o(N) stellt die Zahl 2 ∗ n dar. • Ein Term der Form i(N) stellt die Zahl 2 ∗ n + 1 dar. • Das Atom i stellt die Zahl 1 dar (höchstwertiges Bit). Hinweis: Geben Sie für alle Funktionen, die Sie definieren, Typsignaturen an. 1. Wie würden Sie Binärzahlen mit Hilfe eines Datentypens in Haskell darstellen? Beachten Sie, dass Ihr Darstellung bzgl. des Höchstwertisten Bits der Prolog-Variante entspricht. Im Folgenden verwenden wir den Namen Bin für den neu definierten Datentypen. 2. Definieren Sie zwei Funktionen fromBin :: Bin -> Int und toBin :: Int -> Bin, die Ihren Datentypen in eine Zahl bzw. umgekehrt überführen. Im zweiten Fall betrachten wir nur positive Zahlen, die größer als Null sind; alle anderen Werte sollen einen Fehler liefern. 3. Des Weiteren möchten wir Binärkodierungen spaßeshalber umkehren können; definieren Sie also eine Funktion reverseBin :: Bin -> Bin. Der Aufruf fromBin (reverseBin (toBin 13)) soll z.B. 11 liefern, sprich aus 1101 wird 1011. Insbesondere können wir keinen führenden Nullen darstellen, so dass diese wegfallen, sprich aus 1000 wird 1. 4. Zu guter Letzt wollen wir, dass der Datentyp eine schöne Ausgabe erhält. Geben Sie eine Implementierung an, die den Datentyp Bin wie folgt ausgibt: > show (toBin 8) "IOOO" 10 Punkte Aufgabe 5 - Buzz, buzz, wir brauchen buzz! Das folgende Prolog-Programm definiert ein Prädikat replace(XS,YS), das die Zeichenfolge “bu” durch “zz” ersetzt. replace([] , []). replace([b,u|XS], [z,z|YS]) :- replace(XS, YS). replace([X|XS] , [X|YS]) :- replace(XS, YS). Als Beispiel betrachten wir die folgende Anfrage: ?- replace([b,u,b,u],Z). Z = [z,z,z,z]; Z = [b,u,z,z]; Z = [b,u,z,z,]; Z = [b,u,b,u]; 8 Durch Überlappung der zweiten und dritten Regel erhalten wir durch Backtracking insgesamt vier Lösungen, da für jede mögliche Ersetzung von bu die Zeichenfolge auch erhalten bleiben kann. 1. Bearbeiten Sie eine der folgenden Aufgaben, um die Anfrage ?- replace([a,b,b,u],Res). zu beweisen. Geben Sie für die Anfrage den entstehenden SLD-Baum an, der durch die SLD-Resolution aus der Vorlesung entsteht; die Äste sollen dabei jeweils mit den Variablenbindungen beschriften werden. oder Beweisen Sie die Anfrage mit der Auswertungsstrategie von Prolog. 2. Modifizieren Sie die Implementierung von replace durch das Einfügen eines einzigen Cuts (!) so, dass das Prädikat alle Vorkommen von bu durch zz ersetzt. Es dürfen keine anderen Änderungen vorgenommen werden. So soll die Anfrage ?- replace([b,u,b,u],Z) nur noch Z = [z,z,z,z] als Ergebnis liefern. Erklären Sie mit Hilfe von Teilaufgabe 1, in welchem Schritt der Cut in der Anfrage auftaucht und in welchem Schritt welche Berechnungen wegfallen (Nummerierungen könnten hier hilfreich sein). 10 Punkte Aufgabe 6 - Prolog und Unifikation 1. Wir betrachten das folgende Prolog-Programm. invented(edison,lightbulb). invented(colmeraurer,prolog). iq(einstein,210). iq(edison,160). iq(waldorf,90). genius(Person):- iq(Person,IQ), IQ > 150. genius(Person):- invented(Person,_). a) Was ist die erste Antwort von Prolog für die Anfrage ?- genius(A).? b) Wie viele Antworten gibt uns Prolog insgesamt, wenn wir die Anfrage ?- genius(A) stellen? Sprich, wir geben solange mit ; weitere Lösungen aus, bis die Anfrage terminiert. Zählen Sie dabei auch alle vielfachen Vorkommen! c) Viele vertreten die Meinung, dass Statler das Genie der beiden alten Herren der Muppet-Show ist. Erklären Sie warum, die Anfrage ?- genius(statler) aber dennoch nicht erfüllt ist. d) Mit welcher Anfrage können Sie alle Genies in einer Liste erhalten? 2. Mit welchen der Terme kann man ohwell(X, a(b,c), g(W, [H | T])) unifizieren? Insofern eine Unifikation möglich ist, geben Sie den entsprechenden mgu an; ist keine Unifikation möglich, geben Sie eine kurze Begründung bzgl. des ersten nicht aufzulösenden Disagreement Sets an (Sie müssen jedoch nicht jeden Schritt des Unifikationsverfahrens anwenden, die letztendliche Substitution genügt). a) b) c) d) e) f) g) h) [XH | XT] ohwell(V) ohwell([V | V1]) ohwell(X, a(b,c), g(W, [H | T])) oh(X, a(b,c), g(W, [H | T])) ohwell(r(b,c,s), a(G,H), g(wer, [GG])) ohwell(r(b,QQ,E), a(G,H), G) ohwell(X1, X2, g(234, [])) 9