Fachrichtung 6.2 — Informatik Universität des Saarlandes Tutorenteam der Vorlesung Programmierung 1 Programmierung 1 (Wintersemester 2015/16) Lösungsblatt: Aufgaben für die Zusatztutorien: 1 (Höherstufige Hilfsprozeduren: iter und first) 1 Iteration Aufgabe 1.1 Bei IQ-Tests ist es sehr beliebt, die Probanden Zahlenfolgen analysieren zu lassen. Stellen Sie sich vor, Sie seien Macher eines IQ-Tests. Da das manuelle Erstellen von Zahlenfolgen recht mühsam ist, wollen Sie sich Prozeduren Schreiben, die Ihnen die Arbeit erleichtern: (a) Schreiben Sie eine Prozedur createSimpleNumbers : int → (int → int) → int, die zu einer Zahl n und einer Berechnungsvorschrift, die beschreibt, wie die Folgezahl aus der vorherigen gebildet werden kann, das n-te Element der Zahlenfolge liefert. Alle ihre Zahlenfolgen sollen mit 1 beginnen. Verwenden Sie iter. (b) Nun wäre es auch noch praktisch, wenn Sie die Zahlenfolge in einer Liste ausgeben könnten, um Sie den Probanden vorzulegen. Schreiben Sie also eine Prozedur numberList : int → (int → int) → int list, die zu Anzahl und Berechnungsvorschrift die gesamte Liste, bis zum gegebenen n erzeugt. (c) Aktuell unterliegt createSimpleNumbers noch der Einschränkung, immer bei der Zahl 1 starten zu müssen. Wie könnten Sie dies ändern? Müssten Sie dazu überhaupt eine neue Prozedur schreiben? Lösung 1.1: (a) fun c r ea t e Si m p le N u mb e r s n f = iter n 1 f (b) fun numberList n f = #2( iter n (1 , nil ) ( fn (z , xs ) ⇒ ( f z , xs@ [ z ]))) (c) Die gewünschte Funktionalität entspricht genau iter! Aufgabe 1.2 Schreiben Sie eine Prozedur nrev : α list → int → α list, die eine Liste der Länge n mithilfe von iter reversiert. Lösung 1.2: fun nrev xs n = #1( iter n ( nil , xs ) ( fn ( ys , zs ) ⇒ (( hd zs ):: ys , tl zs ))) Aufgabe 1.3 Schreiben Sie eine Prozedur valueList : α → int → α list, die zu einem übergebenen Wert x und einer Anzahl n, eine n-elementige Liste liefert, in der ausschließlich x vorkommt. Nutzen Sie dazu iter. Lösung 1.3: fun valueList x n = iter n nil ( fn xs ⇒ x :: xs ) Aufgabe 1.4 Schreiben Sie eine Prozedur numberList : int → int → int list, die ab einem gegebenen Anfangswert die ersten n Zahlen hintereinander in eine Liste schreibt. Verwenden Sie iter. 1 Lösung 1.4: fun numberList s n = #2( iter n (s , nil ) ( fn (s ’ , xs ) ⇒ (s ’+1 , xs@ [s ’]))) Aufgabe 1.5 Schreiben Sie die Ihnen bekannte Listenprozedur foldl mithilfe von iter. Sie dürfen die bekannte Prozedur length : α list → int verwenden, die die Länge einer Liste liefert. Lösung 1.5: fun myFoldl f s xs = #1( iter ( length xs ) (s , xs ) ( fn (s ’ , xr ) ⇒ ( f ( hd xr , s ’) , tl xr ))) Aufgabe 1.6 Schreiben Sie eine Prozedur intoList: int → int → (int → α) → α list, die gegeben zwei Zahlen a und b und eine Prozedur f eine Liste mit f angewendet auf alle Zahlen von a bis b zurückgibt: [f a, f (a+1), . . . , f b]. Verwenden Sie dazu ausschließlich iterdn. Lösung 1.6: fun intoList a b f = iterdn b a nil ( fn (x , ys ) ⇒ ( f x ):: ys ) Aufgabe 1.7 Schreiben Sie eine Prozedur f: int → int, dir für eine einstellige Zahl n die Zahl berechnet, deren Ziffern die absteigende Reihe ab n sind. Beispielsweise soll f 5 zu 54321 auswerten. Verwenden Sie dazu ausschließlich die Prozedur iterdn. Lösung 1.7: fun f n = iterdn n 1 0 ( fn (a , b ) ⇒ b *10+a ) Aufgabe 1.8 (a) Schreiben Sie eine Prozedur sumEven: int → int→ int, die gegeben zwei Zahlen a und b alle geraden Zahlen von a bis b aufsummiert. Benutzen Sie dazu ausschließlich die Prozedur iterup. (b) Schreiben Sie nun eine Prozedur sumOdd: int → int → int, die alle ungeraden Zahlen von a bis b aufsummiert. Benutzen Sie hierfür iterdn. (c) Machen Sie sich klar, wie Sie Ihre Prozeduren verändern müssen, wenn Sie sie mit der jeweils anderen Hilfsprozedur schreiben wollen würden (sumEven mit iterdn und sumOdd mit iterup). Lösung 1.8: (a) fun sumEven a b = iterup a b 0 ( fn (x , y ) ⇒ if x mod 2 = 0 then x+y else y ) (b) fun sumOdd a b = iterdn b a 0 ( fn (x , y ) ⇒ if x mod 2 = 1 then x+y else y ) (c) Die Abstraktion kann beibehalten werden, lediglich der Name der Hilfsprozedur (iterup / iterdn) sowie die Reihenfolge der Argumente muss angepasst werden. 2 First Aufgabe 1.9 Ein Fixpunkt x ∈ N für eine Funktion f : N → N ist eine Zahl x, sodass f (x) = x gilt. Schreiben Sie eine Prozedur lfp : (int → int) → int, die den kleinsten Fixpunkt einer übergebenen Prozedur berechnet! 2 Lösung 1.9: fun lfp f = first 0 ( fn x ⇒ f ( x ) =x ) Aufgabe 1.10 Implementieren Sie eine Prozedur, die für positive Zahlen x, y dasselbe Ergebnis liefert wie x div y. Benutzen Sie hierzu first und keine zusätzliche Rekursion. Lösung 1.10: fun mydiv x y = ( first 0 ( fn s ⇒ y * s > x )) − 1 Aufgabe 1.11 Gegeben sei die Prozedur: fun until ’ n p = if ( p n ) then until ’ ( n+1) p else n−1 fun until p = until ’ 0 p • Erklären Sie die Funktionsweise von until! • Verwenden Sie first, um eine semantisch äquivalente Prozedur zu until zu schreiben! • Verwenden Sie until, um eine semantisch äquivalente Prozedur zu first zu schreiben! Lösung 1.11: • until gibt die natürliche Zahl aus, bis zu der das Prädikat (inklusive erfüllt ist). Erfüllt schon 0 das Prädikat nicht, so gibt until −1 zurück. • fun neg x = if x then false else true fun until ’ ’ p = ( first 0 ( fn x ⇒ neg ( p x ))) − 1 • fun first ’ s p = until ( fn x ⇒ x<s orelse neg ( p x )) + 1 Aufgabe 1.12 Schreiben Sie mit Hilfe von first eine Prozedur first2 : (int → bool) → int, die ein Prädikat p erhält, und die zweitkleinste Zahl zurückgibt, die p erfüllt. Lösung 1.12: fun first s f = first (( first s f )+1) f Aufgabe 1.13 Schreiben Sie mit Hilfe von first und iter eine Prozedur nth_first: int → (int → bool) → int, die ein Prädikat p erhält, und die n-t kleinste Zahl zurückgibt, die p erfüllt. Lösung 1.13: fun first_nth n s f = ( iter n s ( fn x ⇒ 1 + first x f )) − 1 Aufgabe 1.14 Schreiben Sie mit Hilfe von first eine Prozedur ggT: int → int → int, die den größten gemeinsamen Teiler zweier natürlichen Zahlen x und y berechnet - d.h. die maximale Zahl n, die sowohl x als auch y teilt. Hinweis: Gehen Sie von oben an die Aufgabe heran! 3 Lösung 1.14: fun ggT x y = let val max = if x>y then x else y in max − first 0 ( fn z ⇒ x mod ( max − z ) = 0 andalso y mod ( max − z ) = 0) end 4