IS S S A R E R S IT S UN IV A Fachrichtung 6.2 — Informatik Universität des Saarlandes Tutorenteam der Vorlesung Programmierung 1 A VIE N 06.02.2016 Programmierung 1 Probeklausur zur Hauptklausur Matrikelnummer: • Bitte öffnen Sie das Klausurheft erst dann, wenn Sie dazu aufgefordert werden. • Prüfen Sie dann zuerst, ob Sie alle 15 Seiten dieser Klausur erhalten haben. • Hilfsmittel sind nicht zugelassen. Am Arbeitsplatz dürfen nur Schreibgeräte, Getränke, Speisen und Ausweise mitgeführt werden. Taschen und Jacken müssen an den Wänden des Klausursaals zurückgelassen werden. Mobiltelefone sind ebenfalls dort ausgeschaltet aufzubewahren. • Das Verlassen des Saals ohne Abgabe des Klausurhefts gilt als Täuschungsversuch. • Wenn Sie während der Bearbeitung zur Toilette müssen, geben Sie bitte Ihr Klausurheft bei der Aufsicht ab. Zu jedem Zeitpunkt kann immer nur eine Person zur Toilette. • Alle Lösungen müssen auf den bedruckten rechten Seiten des Klausurhefts notiert werden. Die leeren linken Seiten dienen als Platz für Skizzen und werden nicht korrigiert. Notizpapier ist nicht zugelassen. Sie können mit Bleistift schreiben. • Vorhergehende Teilaufgaben dürfen verwendet werden, auch wenn sie nicht gelöst wurden. • Für die Bearbeitung der Klausur stehen 120 Minuten zur Verfügung. Insgesamt können 120 Punkte und 10 Bonuspunkte erreicht werden. Zum Bestehen der Klausur genügen 60 Punkte. • Bitte legen Sie zur Identifikation Ihren Personalausweis oder Reisepass sowie Ihren Studierendenausweis neben sich. Viel Erfolg! Punkte A1 25 A2 7 A3 15 A4 10 A5 15 A6 20 1 A7 13 A8 10 A9 5 Bonus 10 Gesamt 120 + 10 Matrikelnummer: Seite 2 von 15 Sie dürfen folgende Strukturen verwenden: Prozeduren: • foldl : (α * β → β) → β → α list → β • foldr : (α * β → β) → β → α list → β • iter : int → α → (α → α) → α • iterup : int → int → α → (int * α → α) → α • iterdn : int → int → α → (int * α → α) → α • first : int → (int → bool) → int • map : (α → β) → α list → β list • rev : α list → α list • List.length : α list → int • List.concat : α list list → α list • List.tabulate : int * (int → α) → α list • List.filter : (α → bool) → α list → α list • List.exists : (α → bool) → α list → bool • List.all : (α → bool) → α list → bool • List.nth : (α list * int) → α • hd : α list → α • tl : α list → α list • Int.compare : int * int → order • null : α list → bool • fold : (α list → α) → tree → α • explode : string → char list • implode : char list → string • chr : int → char • ord : char → int • match : α * token list → token → α * token list • extend : α * token list → (token list → β * token list) → (α * β → γ) → γ * token list Datentypen: • datatype tree = T of tree list • Vector-Signatur: eqtype α vector val fromList: α list → α vector val tabulate: int * (int → α) → α vector val sub: (α vector * int) → α (*Subscript*) val length: α vector → int val map: (α → β) → α vector → β vector val update = α vector * int * α → α vector val foldl: (α * β → β) → β → α vector → β val foldr: (α * β → β) → β → α vector → β val concat: α vector list → α vector Matrikelnummer: Aufgabe 1: Zum Aufwärmen Seite 3 von 15 (10 + 5 + 2 + 8 = 25) Punkte Teilaufgabe 1.1 Schreiben Sie eine Prozedur sort: (α * α → order) → α list → α list, die eine Liste strikt aufsteigend sortiert. Teilaufgabe 1.2 Schreiben Sie eine Prozedur compare, die reine Bäume bezüglich ihrer Größe vergleicht. Matrikelnummer: Seite 4 von 15 Teilaufgabe 1.3 Schreiben Sie eine Prozedur vom Typ f: (α → β) * (γ → α) → γ → β ohne Verwendung von Konstanten und expliziten Typangaben. Teilaufgabe 1.4 Wie im Buch seien Umgebungen durch type α env = string → α definiert. (a) Stellen Sie die leere Umgebung empty: α env dar. exception Unbound of string val empty = (b) Schreiben Sie eine Prozedur update: α env → string → α → α env, die eine Umgebung um eine zusätzliche Bezeichnerbindung erweitert. (c) Stellen Sie die Umgebung [x := 42, y := 25] mithilfe von empty und update dar. Matrikelnummer: Seite 5 von 15 Aufgabe 2: Mathematische Prozeduren (7) Punkte Teilaufgabe 2.1 Zeigen Sie mithilfe des Korrektheitssatzes, dass die Prozedur p:N→N p n = if n < 1 then 1 else p(n − 1) + 2n + 1 die Funktion λn ∈ N.(n + 1)2 berechnet. Matrikelnummer: Seite 6 von 15 Aufgabe 3: Induktive Korrektheitsbeweise (15) Punkte Teilaufgabe 3.1 Zeigen Sie mit Hilfe von struktureller Induktion, dass ∀xs ∈ L(X) : foldl(f, nil, xs) = rev(map(g, xs)) mit f = λ(x, xs) ∈ X × L(X). g(x) :: xs. Sie dürfen annehmen, dass die Konkatenation von Listen assoziativ ist, das heißt xs@(ys@zs) = (xs@ys)@zs. Die Definitionen von map und foldl seien wie folgt gegeben: map ∈ (X → Y ) × L(X) → L(Y ) map(f, nil) = nil map(f, x :: xs) = f (x) :: map(f, xs) foldl ∈ ((X × Y ) → Y ) × Y × L(X) → (Y ) foldl(f, s, nil) = s foldl(f, s, x :: xs) = foldl(f, f (x, s), xs) Matrikelnummer: Seite 7 von 15 Aufgabe 4: Laufzeit (8 + 2 = 10) Punkte Teilaufgabe 4.1 Bestimmen Sie die Komplexität folgender mathematischer Objekte. Begründen Sie Ihre Ergebnisse. (a) p:N×N×N→N p(0, 0, z) = z p(x, y, z) = if x > y then 5 · p(x − 1, y, z + x) else x · x · x + p(x, y − 1, z + y) für x > 0 oder y > 0 (b) d∈N→N d(n) = 2n n < 500 n d(n) = 20 + d b c 2 n ≥ 500 Teilaufgabe 4.2 (a) Geben Sie die Komplexität der durch die folgende Gleichung rekursiv definierten Funktion f ∈ N → N an: f (n) = if n = 0 then 0 else f (n − 1) (b) Geben Sie die Komplexität der durch die folgende Gleichung rekursiv definierten Prozedur f : N → N an: f (n) = if n = 0 then 0 else f (n − 1) Matrikelnummer: Seite 8 von 15 Aufgabe 5: Statische und dynamische Semantik (15) Punkte Es sei eine abstrakte Grammatik, Typen und Werte wie folgt gegeben: fin z∈Z t ∈ T y = int T ∈ TE = Id −−* Ty x ∈ Id = N e ∈ Exp = z | x | ++ e v ∈ Val = Z V ∈ VE = Id −−* Val fin Die obigen Ausdrücke, Typen, Werte und Umgebungen werden mit folgenden Typdeklarationen dargestellt: datatype datatype datatype datatype exp = Num of int | Id of string | Increment of exp ty = Int value = IV of int α env = string → α Der Inkrement-Operator ist ein unärer Operator ++ : Z → Z, welcher eine ganze Zahl inkrementiert (also um eins erhöht). So wertet beispielsweise ++ 5 zu 6 aus. Teilaufgabe 5.1 (a) Vervollständigen Sie die Inferenzregeln für die statische Semantik. SIncr SNum T ` SId T ` T ` (b) Schreiben Sie nun eine Prozedur elab: ty env → exp → ty, welche nach obigen Inferenzregeln prüft, ob ein Ausdruck wohlgetypt ist und dessen Typ zurückgibt. Matrikelnummer: Seite 9 von 15 Teilaufgabe 5.2 (a) Vervollständigen Sie die Inferenzregeln für die dynamische Semantik. DIncr DNum V ` DId V ` V ` (b) Schreiben Sie eine Prozedur eval: value env → exp → value, welche den Ausdruck nach obigen Inferenzregeln auswertet. Matrikelnummer: Seite 10 von 15 Aufgabe 6: Konkrete Syntax (3 + 10 + 7 = 20) Punkte Es gibt zwei Operatoren für reguläre Ausdrücke: Kleene’scher Stern • ∗ ∗ und Vereinigung +. klammert stärker als +. • + klammert implizit links (wie die arithmetischen Operatoren auch). • ∗ ist ein unärer Operator, d. h. ist ϕ ein regulärer Ausdruck, so ist ϕ∗ auch ein regulärer Ausdruck. • + ist ein binärer Operator, d. h. sind ϕ und ψ reguläre Ausdrücke, so ist es auch ϕ + ψ. Wortfolgen werden mit den folgenden Token dargestellt: datatype token = STERN | PLUS | CON of string | LPAR | RPAR Gültige Ausdrücke wären z.B. A + B + C ∗ , A∗ und (A + B)∗ . Konstanten sind also beliebige Strings. Obige Regeln führen zu folgender Grammatik: plusexp ::= [plusexp “+”] sternexp sternexp ::= pexp [“*”] pexp ::= con | “(”plusexp“)” Hierbei bezeichnet con einen beliebigen String. Teilaufgabe 6.1 Machen Sie die Grammatik RA-tauglich. Matrikelnummer: Seite 11 von 15 Teilaufgabe 6.2 Schreiben Sie einen Parser zu Ihrer Grammatik. Verwenden Sie dabei den folgenden Konstruktortyp exp: datatype exp = Stern of exp | Plus of exp * exp | Con of string Matrikelnummer: Seite 12 von 15 Teilaufgabe 6.3 Wir betrachten eine Teilsprache von Standard ML, die nur aus beliebig geklammerten arithmetische Ausdrücken gebildet mit Ganzzahlkonstanten und + besteht. Außerdem seien Kommentare erlaubt. Ein Kommentar beginnt immer mit (* und endet mit *). Alles was zwischen Anfang und Ende des Kommentars steht, soll vom Lexer ignoriert werden. Schreiben Sie einen Lexer, der folgende Tokens aus einer char list ausliest. datatype token = ADD | CON of int | LPAR | RPAR fun lexInt s v cs = if null cs orelse not(Char.isDigit (hd cs)) then CON(s*v):: lex cs else lexInt s (10*v+(ord(hd cs)−ord#"0")) (tl cs) and lex Matrikelnummer: Aufgabe 7: Datenstrukturen Seite 13 von 15 (4 + 9 = 13) Punkte Teilaufgabe 7.1 (a) Implementieren Sie einen Konstruktortyp iLtr, welcher markierte Bäume darstellt. Es soll in konstanter Zeit auf die Unterbäume zugegriffen werden können. (b) Implementieren Sie nun eine Prozedur label: α iLtr → int list → α, welche die Markierung eines markierten Baumes an einer Adresse liefert. Teilaufgabe 7.2 Betrachten Sie die folgende Signatur für Mengen von ganzen Zahlen: signature SET = sig type set val set : int list → set val Z : set val member : int → set → bool val negate : set → set end set ist der Typ Ihrer Darstellung der Mengen. Die Prozedur set verwandelt eine int list in ein endliches set; mit Z erhalten wir die Menge der ganzen Zahlen. member implementiert ∈ und negate das Mengenkomplement. Das Komplement A einer Menge A ist die Menge, die genau alle ganzen Zahlen enthält, die nicht in A sind. Implementieren Sie eine Struktur, die diese Signatur realisiert. Matrikelnummer: Aufgabe 8: Speicher und veränderliche Objekte Seite 14 von 15 (6 + 4 = 10) Punkte Teilaufgabe 8.1 Schreiben Sie foldl mithilfe von map. Teilaufgabe 8.2 Schreiben Sie einen Generator fgen: unit → int für die Kubikzahlen. Aufgabe 9: Stapelmaschinen (5) Punkte Teilaufgabe 9.1 Schreiben Sie ein Maschinenprogramm, das folgenden Ausdruck auswertet: 18 + (2 + 34) · (7 − 3) Matrikelnummer: Aufgabe 10: Bonusaufgabe Seite 15 von 15 (10) Bonuspunkte Teilaufgabe 10.1 Beim Experimentieren mit Ihrem Interpreter sind Sie auf einen geheimnisvollen Typ blackbox gestoßen. Dieser ist weder ein Typ mit Gleichheit noch haben Sie eine Vergleichsprozedur finden können. Allerdings steht Ihnen eine Prozedur ssort: blackbox list → blackbox list zur Verfügung, die eine Liste von Elementen dieses Typs strikt aufsteigend sortiert. Schreiben Sie damit eine Prozedur sort: blackbox list → blackbox list, die eine Liste nicht-strikt sortiert.