Fachrichtung 6.2 — Informatik Universität des Saarlandes Tutorenteam der Vorlesung Programmierung 1 Programmierung 1 (Wintersemester 2015/16) Aufgaben für die Übungsgruppen: 3 (Kapitel 3) Hinweis: Dieses Übungsblatt enthält von den Tutoren für die Übungsgruppe erstellte Aufgaben. Die Aufgaben und die damit abgedeckten Themenbereiche sind für die Klausur weder relevant noch irrelevant. 1 Höherstufigkeit Höherstufigkeit verstehen Hinweis: Bearbeiten Sie diesen Abschnitt nur, wenn Sie noch grundlegende Verständnisprobleme zu Höherstufigkeit, insbesondere zu iter haben. Ansonsten empfehlen wir Ihnen, diese Aufgaben zu überspringen. Aufgabe 3.1 Sei folgender Code gegeben: fun f a b = iter a b ( fn x ⇒ x + 1) Geben Sie ein verkürztes Ausführungsprotokoll für den Aufruf f 4 9 an. Aufgabe 3.2 Sei folgender Code gegeben: fun istprim ( n : int ) : bool = ... fun f a = first a istprim Dabei liefert istprim genau dann true, wenn die Eingabe n eine Primzahl ist. Geben Sie ein verkürztes Ausführungsprotokoll für den Aufruf f 14 an. Aufgabe 3.3 Sei folgender Code gegeben: fun sum ( f : int → int ) ( n : int ) : int = if n < 1 then 0 else sum f ( n − 1) + f n fun pluszwei x = x + 2 Geben Sie ein verkürztes Ausführungsprotokoll für den Aufruf sum pluszwei 4 an. Aufgabe 3.4 Sei folgender Code gegeben: fun f a b g = iter ( b − a + 1) (a , 0) ( fn (n , x ) ⇒ ( n + 1 , x + ( if g n then 1 else 0))) (a) Welchen Typ hat f ? (b) Geben Sie ein verkürztes Ausführungsprotokoll für den Aufruf f 2 5 (fn n ⇒ n mod 2 = 0) an. Hinweis: Sie dürfen häufig auftretende Codeschnipsel (beispielsweise Abstraktionen, die unverändert als Argument weitergegeben werden) abkürzen. 1 Höherstufigkeit anwenden Aufgabe 3.5 (a) Schreiben Sie eine höherstufige Prozedur, die nicht kaskadiert ist. (b) Schreiben Sie eine kaskadierte Prozedur, die nicht höherstufig ist. Aufgabe 3.6 Schreiben Sie eine Prozedur quad : int → int, welche mit Hilfe von iter eine Zahl quadriert. Nutzen Sie dafür keine Multiplikation. Aufgabe 3.7 Schreiben Sie eine Prozedur double : int → int, welche mit Hilfe von iter eine Zahl verdoppelt. Nutzen Sie dafür keine Multiplikation Aufgabe 3.8 Schreiben Sie eine Prozedur gerade: int → bool, die für eine Zahl n prüft, ob sie gerade oder ungerade ist. Verwenden Sie dazu ausschließlich iter und weder die Operation mod noch div. Aufgabe 3.9 Deklarieren Sie eine Prozedur aufrundenBitte : int → int, die eine gegebene Zahl auf die nächstgrößere durch 10 teilbare Zahl aufrundet. Benutzen Sie first, aber keine explizierte Rekursion! Aufgabe 3.10 Schreiben Sie zwei Prozeduren cas : ( int * int → int ) → int → int → int car : ( int → int → int ) → int * int → int so, dass cas zur kartesischen Darstellung einer zweistelligen Operation die kaskadierte Darstellung und car zur kaskadierten Darstellung die kartesische Darstellung liefert. Erproben Sie cas und car mit einem Interpreter! Aufgabe 3.11 Schreiben Sie eine Prozedur summe: int * int → int, die zu zwei gegebenen natürlichen Zahlen m und n (wobei m < n) die Summe (m + 1) + (m + 2) + (m + 3) + ... + (n − 1) berechnet. Verwenden Sie hierzu: (a) iterup (b) iterdn (c) iter Aufgabe 3.12 Schreiben Sie eine Prozedur kubik: int → int, die die erste Kubikzahl bestimmt, die strikt größer ist als eine Eingabe n. Aufgabe 3.13 Schreiben Sie eine Prozedur count: (int → bool) → int → int → int, die zählt, wie oft eine übergebene Prozedur predicate zwischen zwei Zahlen min und max (jeweils inklusive) true liefert. Aufgabe 3.14 (a) Schreiben Sie eine Prozedur quer: int → int, die zu einer gegebenen ganzen Zahl n die Quersumme berechnet. Verwenden Sie iter. Hinweis: Sie benötigen eine Hilfsprozedur stell: int → int, die Ihnen die Stelligkeit einer Zahl berechnet. (b) Implementieren Sie nun eine Prozedur equalquer: int → int, die zu einer gegebenen natürlichen Zahl n die kleinste natürliche Zahl berechnet, deren Quersumme gleich der Quersumme von n ist. 2 Aufgabe 3.15 (Primzahlen I ) Geben Sie einen Ausdruck vom Typ int → int an, der zu einer Eingabe n > 2 die größte Primzahl liefert, die echt kleiner ist als n. Nehmen Sie eine Prozedur istprim: int → bool, die genau dann true liefert, wenn ihre Eingabe prim ist, als gegeben an. Aufgabe 3.16 (k-Fibonacci) (a) Schreiben Sie eine Prozedur fib3: int → int, die die n-te 3-Fibonacci-Zahl berechnet, d. h. die drei Vorgänger werden addiert. Die definierenden Gleichungen lauten: f ib3 n = 0 n<3 f ib3 n = 1 n=3 f ib3 n = f ib3 (n − 1) + f ib3 (n − 2) + f ib3 (n − 3) n>3 Die Folge beginnt wie folgt: 0, 0, 0, 1, 1, 2, 4, 7, 13, 24, . . . (b) Zeichnen Sie den Rekursionsbaum für n = 6. (c) Geben Sie ein verkürztes Ausführungsprotokoll für fib3 5 an. (d) Schreiben Sie eine Prozedur fibk: int → int → int, welche mithilfe von iterup die n-te k-FibonacciZahl berechnet. Für die n-te k-Finbonacci-Zahl werden die k Vorgänger addiert, wenn n > k. Für alle n < k soll gelten: fibk n = 0. Für n = k ist fibk n = 1. Aufgabe 3.17 (Primzahlen II ) Schreiben Sie eine Prozedur istprim: int → bool, die entscheidet, ob eine Zahl n ≥ 2 eine Primzahl ist. j nk Hinweis: Wann gilt n = · k? Wie können Sie diese Gleichung mit first ausnutzen? k 2 Typinferenz Aufgabe 3.18 Geben Sie Deklarationen an, welche die folgenden Bezeichner monomorph typen: (a) a: (bool → real) * int * bool (b) b: unit → unit (c) c: (bool * int * bool → int) → bool * int * bool → int (d) d: unit → real → bool (e) e: (int * int → bool) → real Verzichten Sie dabei auf explizite Typangaben und verwenden Sie keine Operator- und Prozeduranwendungen. Aufgabe 3.19 Bestimmen Sie das Typschema folgender Prozeduren: (a) fun f a b = a b b (b) fun f a b c = a b c (c) fun f a b c = a (b c) (d) fun f a (b, c) = (a b, a c, a b c) (e) fun f (a, b, c) d = if c then (a+4)=b else d (true) (f) fun f (a,b,c,d) = if a<3 then b else if c=d then 5.3 else 3.8 (g) fun f a b (c,d) = let val e=(a b) in if c then d else d+2 end 3 (h) fun f a (b, c) d = a (b (c d) c a) (i) fun f a (b,c) d (e,f) = a (f e) ((a b) (c d)) Aufgabe 3.20 Gegeben sei folgendes Programm: fun f x y = x = y fun g x h = fn y ⇒ let val a = f x val b = h in b a y end (a) Geben Sie jeweils das Typschema von f und g an. (b) Überprüfen Sie Ihre Lösung mit dem Interpreter. Aufgabe 3.21 Geben Sie jeweils eine Prozedur mit dem gegebenen Typschema an, ohne dabei explizite Typangaben zu machen. (a) bool → int → int (b) int → α → β → bool (c) (α → β → γ) → (β → α) →β → γ (d) ’α → ’α → β → (β → β) → β (e) α → (β → γ) → (α → β) → γ (f) α → β → (α → β) → (bool → γ) → γ (g) α → (α → α) → α (h) ((α → β) → γ) → β → γ (i) ((α → β → α) → γ) → (δ → α) → δ → γ (j) α → (β → α) → α (k) α → (β → α → γ) → (β → γ) * (α → α) (l) α → (α → β) → (int → α) * β (m) (α → β) → (α → γ) → α → β * (α → γ) * γ * (bool → γ) (n) (bool → α) → ’β → (α * ’β → ’β * γ) → γ → ’β (o) (bool → bool) → α → β → γ → (β * γ → (bool → bool) * γ) → bool Aufgabe 3.22 Gibt es ein Typschema, für das sich keine Prozedur mit diesem Typschema finden lässt? 3 Bezeichnerbindung Aufgabe 3.23 Gegeben sei die folgende Prozedurdeklaration: fun g x y = (fn x ⇒ let val x = f x val y = g x y in x + y end) x Bereinigen Sie die Prozedurdeklaration: Überstreichen Sie die definierenden Bezeichnerauftreten, stellen Sie die lexikalischen Bindungen mit Pfeilen dar und benennen Sie konsistent die gebundenen Bezeichner um. 4