Beispiellösung zum Übungsblatt aus Wiederholungstutorium 2

Werbung
Fachrichtung 6.2 — Informatik
Universität des Saarlandes
Tutorenteam der Vorlesung Programmierung 1
Programmierung 1 (Wintersemester 2015/16)
Wiederholungstutorium Lösungsblatt 2
(Höherstufige Prozeduren, Typinferenz)
Hinweis: Dieses Übungsblatt enthält von den Tutoren für das Wiederholungstutorium erstellte Aufgaben.
Die Aufgaben und die damit abgedeckten Themenbereiche sind für die Klausur weder relevant noch irrelevant.
Typen, Bindungen und Bezeichner
Aufgabe 2.1 (Typschema 1 )
Bestimmen Sie die Typschemata folgender Prozeduren:
(a) fun p x y = if x then y else 2.0
(b) fun q x = #1((), x=3)
(c) fun r f a b = f(a,b)
(d) fun s n f x = if n < 100 then x else f(x)
(e) fun t f x y = if x < 1 then f(x,y) else f(y,x)
Lösung 2.1:
(a) p: bool → real → real
(b) q: int → unit
(c) r: ((α * β) → γ) → α → β → γ
(d) s: int → (α → α) → α → α
(e) t: ((int * int) → α) → int → int → α
Aufgabe 2.2 (Typinferenz)
Schreiben Sie Prozeduren mit folgenden Typschemata, ohne dabei explizite Typangaben zu verwenden:
(a) (bool * int) → int
(b) int → bool → int → unit
(c) ∀αβ. int → α → (α → β) → α
(d) ∀αβ. ’α → (’α * β) → β → β
(e) ∀αβγ. (α
* (β → α → γ)) → (α → β) → γ
Lösung 2.2:
(a) fun a (x , y ) = if x then y else 3
(b) fun b x y z = if y then #2( x+z ,()) else ()
(c) fun c x y f = if x < 1 then y else #1( y , f ( y ))
(d) fun d x ( y1 , y2 ) z = if x = y1 then y2 else z
(e) fun e (x , f ) g = ( f ( g x ) x )
1
Aufgabe 2.3 (Typschema 2 )
Geben Sie die Typschemata folgender Bezeichner an:
(a) val a = fn x ⇒ ( fn y ⇒ if y then x else 3)
(b) val b = fn x ⇒ ( fn y ⇒ ( fn f ⇒ f (x , y ) true ))
(c) val c = let fun f x y = if x then y else 2
in ( fn t ⇒ fn s ⇒ ( f s t ,()))
end
Lösung 2.3:
(a) a: int → bool → int
(b) a: α → β → ((α * β) → bool → γ) → γ
(c) b: int → bool → (int * unit)
Aufgabe 2.4 (Bezeichnerbindungen)
Bereinigen Sie folgende Prozedurdeklaration: Überstreichen Sie die definierenden Bezeichnerauftreten, stellen Sie
die lexikalischen Bindungen mit Pfeilen dar und benennen Sie konsistent die gebundenen Bezeichner um.
fun g x y = ( fn x ⇒ let val x = f x val y = g x y in x + y end ) x
Lösung 2.4:
fun g1 x1 y1 = ( fn x2 ⇒ let val x3 = f x2 val y2 = g1 x2 y1 in x3 + y2 end ) x1
Lexikalische Bindungen: Ziehe einen Pfeil von jedem indizierten, benutzenden Bezeichnerauftreten zu dem gleich
indizierten, überstrichenen Bezeichnerauftreten.
Aufgabe 2.5 (Bindungsprobleme)
Bereinigen Sie das folgende Programm durch Überstreichen der definierenden und Indizieren der gebundenen
Bezeichnerauftreten.
val
fun
val
fun
(x , y ) = (2 ,3)
f x = fn x ⇒ #1( x , y )
y = x*y
g g = f x g
Machen Sie sich zunächst klar, wie die Deklaration der Prozedur g zu verstehen ist.
Lösung 2.5:
val
fun
val
fun
(x1 ,
f1 x2
y2 =
g1 g2
y1 ) = (2 ,3)
= fn x3 ⇒ #1( x 3 ,y 1 )
x1 * y1
= f1 x1 g2
Kaskadierte und Höherstufige Prozeduren
Aufgabe 2.6 (Konstant)
Schreiben Sie eine Prozedur constant: α → β → α nach Möglichkeit auf drei verschiedene Weisen: kaskadiert,
mit einer lokalen Deklaration und mit einer Abstraktion. Die Prozedur soll immer konstant das erste Argument
zurückgeben, egal was als zweites Argument eingegeben wird.
2
Lösung 2.6:
• fun constant x y = x
• fun constant x = let
fun const y = x
in
const
end
• fun constant x = ( fn y ⇒ x )
Aufgabe 2.7 (Kaskadiert und höherstufig)
Schreiben Sie folgende Prozeduren:
(a) eine höherstufige Prozedur, die nicht kaskadiert ist.
(b) eine kaskadierte Prozedur, die nicht höherstufig ist.
(c) eine höherstufige, kaskadierte Prozedur.
Lösung 2.7:
(a) fun f ( x : int → int ) : int = 4
(b) fun f x y = x + y
(c) fun f g x = g x
Aufgabe 2.8 (Konvertieren)
Schreiben Sie zwei Prozeduren
(a) cas: (int * int → int) → int → int → int
(b) 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.
Lösung 2.8:
(a) fun cas ( f : int * int → int ) ( x : int ) ( y : int ) = f (x , y )
(b) fun car ( f : int → int → int ) ( x : int , y : int ) = f x y
Aufgabe 2.9 (Höherstufiges Produkt)
Deklarieren Sie eine Prozedur prod: (int → int) → int → int, die für n > 0 die Gleichung
prod f n = 1·(f 1)·. . .·(f n) erfüllt. Deklarieren Sie außerdem mithilfe von prod eine Prozedur fac: int → int,
die für n > 0 die Fakultät n! berechnet.
Lösung 2.9:
fun prod f n = if n<1 then 1 else ( f n ) * prod f ( n−1)
fun fac z = prod ( fn y ⇒ y ) z
3
Aufgabe 2.10 (Primzahlen 1 )
Deklarieren Sie zunächst eine Prozedur forall: int → int → (int → bool) → bool, sodass forall m n p
genau dann true liefert, wenn p für alle natürlichen Zahlen von m bis n (inklusive) das Ergebnis true liefert.
Verwenden Sie andalso und orelse.
Schreiben Sie anschließend mithilfe von forall eine Prozedur isprime: int → bool, die testet, ob eine Zahl
x eine Primzahl ist.
Lösung 2.10:
fun forall m n p = m > n orelse ( p m andalso forall ( m+1) n p )
fun isprime x = x >= 2 andalso forall 2 ( sqrt x ) ( fn y ⇒ x mod y <> 0)
Aufgabe 2.11 (Wahrheitszähler)
Schreiben Sie eine Prozedur tcount: int → int → (int → bool) → int, welche zu zwei Zahlen n, m > 0
die Anzahl der Zahlen v mit n ≤ v ≤ m berechnet, für die eine Prozedur p den Wert true ergibt. Verwenden Sie
eine endrekursive Hilfsprozedur tcount’. Die Prozedur tcount selbst soll nicht rekursiv sein.
Deklarieren Sie außerdem mithilfe von tcount eine Prozedur pcount: int → int, die zählt, wieviele Zahlen
kleinergleich n Primzahlen sind.
Lösung 2.11:
fun tcount ’ a n m f = if n > m then a else if f n then tcount ’ ( a+1) ( n+1) m f
else tcount ’ a ( n+1) m f
fun tcount n m f = tcount ’ 0 n m f
fun pcount z = tcount 0 z isprime
Iter und First
Aufgabe 2.12 (Primzahlen 2 )
Schreiben Sie unter Verwendung der Prozedur isprime aus Aufgabe 2.10 folgende Prozeduren:
(a) nextprime: int → int, sodass nextprime zu einer Zahl n die erste Primzahl x > n liefert.
(b) nthprime: int → int, die für n ≥ 1 die n-te Primzahl liefert.
Lösung 2.12:
(a) fun nextprime n = first ( n+1) isprime
(b) fun nthprime n = iter n 1 nextprime
Aufgabe 2.13 (Iter Rocks)
Deklarieren Sie folgende Prozeduren mithilfe von iter:
(a) add: int → int → int, die zwei Zahlen x, y durch Inkrementieren addiert.
(b) power: int → int → int, zur Berechnung von Potenzen.
(c) sum: int → (int → α) → α, sodass sie für n ≥ 0 die Gleichung sum n f = 0 + f 1 + ... + f n erfüllt.
Benutzen Sie Tupel und eine Projektion.
Lösung 2.13:
(a) fun add x y = iter y x ( fn s ⇒ s+1)
(b) fun power x n = iter n 1 ( fn a ⇒ a * x )
(c) fun sum n f = #1( iter n (0 ,1) ( fn (x , y ) ⇒ ( x + ( f y ) , y+1)))
4
Aufgabe 2.14 (Fakultät)
Deklarieren Sie n! mit iterup.
Lösung 2.14:
fun fac n = iterup 1 n 1 ( fn (x , s ) ⇒ x * s )
Aufgabe 2.15 (Gerade oder ungerade)
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.
Lösung 2.15:
fun gerade n = iter n true not
Alternative:
fun gerade n = iter n true ( fn x ⇒ if x then false else true )
Aufgabe 2.16 (Summe)
Schreiben Sie eine Prozedur gsum: int → int → int, die zu zwei natürlichen Zahlen m, n mit m < n die
Summe m + (m + 1) + . . . + (n − 1) + n berechnet. Verwenden Sie dabei folgende Prozeduren:
(a) iterup
(b) iter
Lösung 2.16:
(a) fun summe (m , n ) = iterup m n 0 ( fn (m , s ) ⇒ m + s )
(b) fun summe (m , n ) = #1( iter ( n−m ) (0 , m+1) ( fn (a , b ) ⇒ ( a + b , b+1)))
Aufgabe 2.17 (Think Diverent)
Schreiben Sie die Prozedur div zur ganzzahligen Division auf folgende alternative Weisen:
(a) fdiv: int → int → int, mithilfe von first.
(b) idiv: int → int → int, mithilfe von iter.
Hinweis: Verwenden Sie Tupel und eine Projektion für Aufgabenteil b).
Lösung 2.17:
(a) fun fdiv x y = ( first 0 ( fn a ⇒ a * y > x )) − 1
(b) fun idiv x y = #1( iter x (0 ,1) ( fn (z , v ) ⇒ if v = y then ( z+1 ,1)
else (z , v+1)))
5
Aufgabe 2.18 (First erweitern)
Deklarieren Sie folgende Prozeduren:
(a) eine Prozedur second: (α → true) → int, die die zweite Zahl x > 0 findet, für die eine Prozedur p
den Wert true ergibt. Verwenden Sie first.
(b) eine Prozedur, die allgemein die k-te Zahl findet, für die eine Prozedur p true ergibt.
Lösung 2.18:
(a) fun first s p = if p s then s else first ( s+1) p
fun second p = let val ersteZahl = first 0 p
in first ( ersteZahl + 1) p end
(b) fun find k p = iter k 0 ( fn x ⇒ first ( x+1) p )
Aufgabe 2.19 (Iter erweitern)
Deklarieren Sie mithilfe der Prozedur iter eine Prozedur:
(a) iterup’, die zu m, n, s, und f dasselbe Ergebnis liefert wie iterup m n s f.
(b) iterdn’, die zu m, n, s, und f dasselbe Ergebnis liefert wie iterdn m n s f.
Lösung 2.19:
(a) fun iterup ’ m n s f = #2( iter ( n−m+1) (m , s ) ( fn (x , a ) ⇒ (( x+1) , f (x , a ))))
(b) fun iterdn ’ m n s f = #2( iter ( n−m+1) (n , s ) ( fn (x , a ) ⇒ (( x−1) , f (x , a ))))
6
Herunterladen