Beispiellösung zum Übungsblatt aus Übung 4

Werbung
Fachrichtung 6.2 — Informatik
Universität des Saarlandes
Tutorenteam der Vorlesung Programmierung 1
Programmierung 1 (Wintersemester 2015/16)
Lösungsblatt: Aufgaben für die Übungsgruppen: 4
(Kapitel 4)
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
Einstieg in Listen
Aufgabe 4.1 (Pattern Matching)
Geben Sie an, welche der folgenden Ausdrücke auf die folgenden Muster passen, und welche Bindungen dabei
erzeugt werden.
Muster →
↓ Wert
(2,4)
([2],[4])
[1,2,3]
[1,3]
[[]]
[[3]]
[(1,2)]
([],[])
((),())
nil::nil
(nil::nil)::nil
nil::nil::nil
Lösung 4.1:
Muster →
↓ Wert
(2,4)
([2],[4])
[1,2,3]
[1,3]
[[]]
[[3]]
[(1,2)]
([],[])
((),())
nil
nil::nil
(nil::nil)::nil
nil::nil::nil
(a,_)
x
[1,_]
_::x::_
a::b
(a::b)::c
(a,_)
x
[1,_]
_::x::_
a::b
(a::b)::c
3
3
7
7
7
7
7
3
3
7
7
7
7
3
3
3
3
3
3
3
3
3
3
3
3
3
7
7
7
3
7
7
7
7
7
7
7
7
7
7
7
3
3
7
7
7
7
7
7
7
7
3
7
7
3
3
3
3
3
7
7
7
3
3
3
7
7
7
7
7
3
7
7
7
7
7
3
7
Aufgabe 4.2
Entscheiden Sie, ob die folgenden Ausdrücke wohlgetypt sind und geben Sie die Typen an.
(a) nil
1
(b) (2 :: nil) :: nil
(c) [(true, 5), (false, 28)]
(d) (nil :: nil) :: 1 :: nil :: nil :: nil
(e) (nil :: nil :: nil) @ nil :: [[]]
Lösung 4.2:
(a) α list
(b) int list list
(c) (bool ∗ int) list
(d) type clash E
(e) α list list
Aufgabe 4.3
Schreiben Sie eine Prozedur count: ’α → ’α list → int, die zählt, wie oft ein Element a in einer Liste
enthalten ist. Nutzen Sie keine Hilfsprozeduren.
Lösung 4.3:
fun count a nil = 0
| count a ( x :: xr ) = ( if x = a then 1 else 0) + count a xr
Aufgabe 4.4
Schreiben Sie eine Prozedur body: α list → α list, welche die Liste ohne das letzte Element zurück gibt,
erst mit und dann ohne die Hilfe von Listenprozeduren. Wenn die übergebene Liste leer ist, soll Empty geworfen
werden.
Lösung 4.4:
fun body xs = rev ( tl ( rev xs ))
fun body ’ nil = raise Empty
| body ’ [ x ] = nil
| body ’ ( x :: xr ) = x :: body xr
Aufgabe 4.5
Schreiben Sie eine Prozedur truesum: (int * bool) list → int, welche eine Liste aus Paaren nimmt, und
die Zahlen aus den Paaren, die als zweite Komponente true haben, aufaddiert und die restlichen außer Acht
lässt. Verzichten Sie auf Konditionale.
Lösung 4.5:
fun truesum nil = 0
| truesum (( x , false ) :: xr ) = truesum xr
| truesum (( x , true ) :: xr ) = x + truesum xr
Aufgabe 4.6
Schreiben Sie eine Prozedur sEven: int list * int list → bool, die für ein Paar von Listen entscheidet,
ob die erste Liste an Position 2 eine 7 und die zweite Liste an Position 1 eine gerade Zahl hat.
Verallgemeinern Sie sEven, sodass kein Paar, sondern eine Liste von Listen als Eingabe genommen wird, wobei
nur die ersten beiden Listen betrachtet werden. Hinweis: sEven’: int list list → bool.
2
Lösung 4.6:
fun sEven ( _ :: _ ::7:: _ , _ :: x :: _ ) = x mod 2 = 0
| sEven _ = false
fun sEven ’ (( _ :: _ ::7:: _ )::( _ :: x :: _ ):: _ ) = x mod 2 = 0
| sEven ’ _ = false
Aufgabe 4.7
Schreiben Sie eine Prozedur kubilist: int → int list, die eine Zahl k als Eingabe nimmt, und die Liste
der Kubikzahlen von k bis 1 liefert. Für k ≤ 0 soll nil zurückgegeben werden. Für k = 3 soll das Ergebnis
[27, 8, 1] lauten.
Lösung 4.7:
fun kubilist k = if k<=0 then nil
else rev ( tl ( List . tabulate ( k+1 , fn x ⇒ x * x * x )))
Alternative:
fun kubilist k = if k<=0 then nil else k * k * k :: kubilist ( k−1)
Aufgabe 4.8
Schreiben Sie eine Prozedur doublemap: (α * β → γ) → α list → β list → γ list, die eine übergebene Prozedur f auf ein Tupel aus je einem Element der beiden übergebenen Listen anwendet. Sind die Listen
unterschiedlich groß, soll die Ausnahme Subscript geworfen werden.
Beispiel: doublemap f [2, 3] [true, false] = [f (2, true), f (3, false)]
Lösung 4.8:
fun doublemap f nil nil = nil
| doublemap f ( x :: xr ) ( y :: yr ) = f (x , y ) :: doublemap f xr yr
| doublemap f _ _ = raise Subscript
Alternative:
fun doublemap f xs ys = f ( hd xs , hd ys ) :: doublemap f ( tl xs ) ( tl ys )
Aufgabe 4.9
Schreiben Sie eine Prozedur confuse: int list → int list, die zunächst prüft, ob eine Liste mindestens
eine gerade Zahl enthält. Falls dem so ist, soll die Liste, die alle ungeraden Zahlen der Eingabeliste enthält,
zurückgegeben werden. Andernfalls werden sämtliche Werte der Eingabeliste verdoppelt und die so entstandene
Liste wird zurückgegeben.
Lösung 4.9:
fun confuse xs = if List . exists ( fn x ⇒ x mod 2 = 0) xs
then List . filter ( fn x ⇒ x mod 2 = 1) xs
else map ( fn x ⇒ 2* x ) xs
2
Strings
Aufgabe 4.10
Schreiben Sie eine Prozedur abc: string → int, die berechnet, wie oft in einem Eingabestring der String
00
abc00 enthalten ist.
3
Lösung 4.10:
fun abc ’ ((# " a " )::(# " b " )::(# " c " ):: xr ) = 1 + abc ’ xr
| abc ’ ( x :: xr ) = abc ’ xr
| abc ’ nil = 0
fun abc eingabe = abc ’ ( explode eingabe )
Aufgabe 4.11
Schreiben Sie eine Prozedur revi: string → string, die einen String bis auf das erste Zeichen reversiert.
Zum Beispiel soll revi(Hallo) = Holla gelten. Handelt es sich um den leeren String oder besteht der String
nur aus einem Zeichen, so soll die Prozedur divergieren. Sie dürfen Hilfsprozeduren verwenden.
Lösung 4.11:
fun revi s = if ( List . length ( explode s )) < 2
then revi s
else implode ( hd ( explode s ) :: ( List . rev ( tl ( explode s ))))
Aufgabe 4.12
Schreiben Sie eine Prozedur isord: string → bool, die für einen gegebenen String prüft, ob die einzelnen
Zeichen innerhalb des Strings der lexikalischen Ordnung entsprechend geordnet sind.
Lösung 4.12:
fun isord s = if ( List . length ( explode s )) < 2
then true
else ( ord ( hd ( explode s ))) < ( ord ( hd ( tl ( explode s ))))
andalso isord ( implode ( tl ( explode s )))
Aufgabe 4.13
Schreiben Sie eine Prozedur remove: char → string list → string list, welche alle Elemente einer Liste
von Strings entfernt, in denen ein übergebenes Zeichen vorkommt. Überlegen Sie hierfür zunächst, welche Ihnen
bekannten Prozeduren hilfreich sein könnten.
Schreiben Sie nun mit Hilfe von remove eine Prozedur removea: string list → string list, die alle
Elemente einer Liste entfernt, in denen ein #00 a00 vorkommt.
Lösung 4.13:
fun remove a xs = List . filter
( fn x ⇒ not ( List . exists ( fn y ⇒ y = a ) ( String . explode x ))) xs
fun removea xs = remove # " a " xs
Aufgabe 4.14
Schreiben Sie eine Prozedur intlist: string → int list, die einen String, der eine Liste von positiven
Zahlen nur durch Komma getrennt enthält, in diese Liste von Zahlen umschreibt. Aus 00 345, 786, 3200 wird
[345,786,32].
Lösung 4.14:
fun intlist ’ (# " ," :: xr ) zahl = zahl ::( intlist ’ xr 0)
| intlist ’ nil zahl = [ zahl ]
| intlist ’ ( x :: xr ) zahl = intlist ’ ( xr ) (10* zahl + ( ord x − ord # " 0 " ))
fun intlist eingabe = intlist ’ ( explode eingabe ) 0
4
3
Faltung
Aufgabe 4.15
Unterscheiden sich foldl op:: nil xs und foldr op:: nil xs?
Lösung 4.15:
foldl op:: nil xs beginnt von links, Elemente an nil anzuhängen, wodurch die Liste reversiert wird.
foldr op:: nil xs gibt schlicht xs zurück. Fertigen Sie jeweils ein Ausführungsprotokoll für [1, 2, 3] an,
um eventuelle Unklarheiten zu beseitigen.
Aufgabe 4.16
Schreiben Sie eine Prozedur double: α list → α list, welche für eine gegebene Liste die Liste zurückgibt,
in der jedes Element doppelt vorkommt.
Lösung 4.16:
fun double xs = foldr (fn (x,s) ⇒ x::x::s) nil xs
Aufgabe 4.17
Schreiben Sie eine Prozedur length’: α list list → int list, die eine Liste von Listen nimmt und eine
Liste mit den Längen der Listen zurückgibt. Für [nil, [1, 2, 8], [5, 2]] lautet die Ausgabe [0, 3, 2].
Lösung 4.17:
fun length ’ xs = foldr ( fn ( ys , akku ) ⇒ ( length ys ):: akku ) nil xs
Aufgabe 4.18
Schreiben Sie eine Prozedur minmax: int list → (int*int), die mit einmal Falten (insgesamt nur einem
Aufruf von foldl bzw. foldr) die kleinste und die größte Zahl einer Liste zurückgibt. Für [3, 6, 2] lautet das
Ergebnis (2, 6).
Lösung 4.18:
fun minmax nil = raise Empty
| minmax ( x :: xr ) =
let
fun f (z , ( min , max )) =
( if z < min then z else min , if z > max then z else max )
in
foldl f (x , x ) xr
end
Aufgabe 4.19
Schreiben Sie eine Prozedur evengreater: int list → bool, die für eine Liste von Zahlen entscheidet, ob sie
mehr gerade als ungerade Zahlen enthält.
Lösung 4.19:
fun evengreater xs = let
val ( gerade , ungerade ) =
foldl ( fn (x , (g , u ) ⇒
if x mod 2 = 0 then ( g+1 , u ) else (g , u+1))) (0 , 0) xs
in
gerade > ungerade
end
Alternative:
fun evengreater xs = #3( foldl ( fn (x ,( a ,b , c )) ⇒ let
val ( gerade , ungerade ) = if x mod 2 = 0 then ( a+1 , b ) else (a , b+1)
5
in
( gerade , ungerade , gerade > ungerade )
end ) (0 , 0 , false ) xs )
Aufgabe 4.20
Schreiben Sie eine Prozedur zip : α list → β list → (α * β) list, die gleichlange Listen zu einer Liste
wie aus dem Typschema ablesbar zusammenfügt. Es soll zip [1,2] [true,false] = [(1,true),(2,false)]
gelten.
Lösung 4.20:
fun zip xs ys = rev (#2( foldl ( fn (x ,( a , ys )) ⇒ (( x , hd ( ys )):: a , tl ( ys )))
( nil , ys ) xs ))
Aufgabe 4.21
Schreiben Sie eine Prozedur primpro: int list → bool, die für eine Liste von Zahlen entscheidet, ob das
Produkt der Primzahlen größer ist als die Summe der Nicht-Primzahlen. Eine Prozedur prim: int → bool,
die sagt, ob eine Zahl eine Primzahl ist, sei gegeben.
Lösung 4.21:
fun primpro xs = let
val ( pro , sum ) = foldl ( fn (x , ( pro , sum )) ⇒
if prim x then ( pro *x , sum ) else ( pro , sum+x )) (1 ,0) xs
in pro > sum end
Aufgabe 4.22
Schreiben Sie eine Prozedur evensmaller: int list → int list list, die eine Liste von Zahlen nimmt und
eine Liste zurückgibt, die zu jedem Element eine Liste mit allen geraden Zahlen zwischen 0 und diesem Element
(jeweils exklusive) enthält. Für [3, 8, 7, 1] lautet die Ausgabe [[2], [2, 4, 6], [2, 4, 6], []].
Lösung 4.22:
fun evensmaller ’ n = if n <=0 then nil else
if n mod 2 = 0 then ( evensmaller ’ ( n−2)) @ [ n ]
else evensmaller ’ ( n−1)
fun evensmaller xs = foldr ( fn (n , akku ) ⇒ ( evensmaller ’ ( n−1)):: akku ) nil xs
Aufgabe 4.23
Schreiben Sie die Listenprozedur foldl mithilfe von iter. Sie dürfen dafür die Prozedur
List.length: α list → int verwenden, die die Länge einer Liste liefert.
Lösung 4.23:
fun myFoldl f s xs = #1( iter ( List . length xs ) (s , xs )
( fn (s ’ , xr ) ⇒ ( f ( hd xr , s ’) , tl xr )))
Aufgabe 4.24
Schreiben Sie eine Prozedur map’: (α → β) → α list → β list, die map mithilfe von Faltung implementiert. Für (fn x ⇒ x div 2) [2, 5, 6, 9] liefert map und somit map’: [1, 2, 3, 4].
Lösung 4.24:
fun map ’ f xs = foldr ( fn (x , akku ) ⇒ ( f x ):: akku ) nil xs
6
Aufgabe 4.25
Schreiben Sie eine Prozedur counta: string list → (string * int) list, die eine Liste von Strings
nimmt, diejenigen behält, die mindestens drei as enthalten, und ihnen die Anzahl von as zuordnet. Für
["abc","bcd","aaaaaz","b","ababa"] lautet die Ausgabe [("aaaaaz",5),("ababa",3)].
Lösung 4.25:
fun counta ’ (# " a " :: xr ) = 1 + counta ’ xr
| counta ’ ( _ :: xr ) = counta ’ xr
| counta ’ nil = 0
fun counta xs = foldr ( fn ( eingabe , akku ) ⇒
if counta ’ ( explode eingabe ) >= 3
then ( eingabe , counta ’ ( explode eingabe )):: akku
else akku ) nil xs
Aufgabe 4.26
Schreiben Sie eine Prozedur clean: string list → string, die eine nicht-leere Liste von Strings nimmt, den
längsten String bestimmt und ihn um alle Ziffern bereinigt zurückgibt.
Für ["abc2","bc1d","a22a3aaaz","b","a1baba"] lautet die Ausgabe "aaaaaz".
Lösung 4.26:
fun clean ( x :: xr ) =
let
fun f (y ,( maxstring , maxlaenge )) =
if List . length ( explode y ) > maxlaenge
then (y , List . length ( explode y ))
else ( maxstring , maxlaenge )
fun rem nil = nil
| rem ( x :: xr ) = if ord x >= ord # " 0 " andalso ord x <= ord # " 9 "
then rem xr else x ::( rem xr )
val lang = #1( foldr f (x , List . length ( explode x )) xr )
in
implode ( rem ( explode lang ))
end
| clean nil = raise Empty
Aufgabe 4.27
Schreiben Sie eine Prozedur thegreatest: int list list → int, die für eine Liste von nicht-leeren Listen von positiven Zahlen entscheidet, die wievielte Liste von Zahlen die insgesamt größte Zahl enthält. Für
[[2, 3, 0], [5], [3, 5, 3, 1]] soll 1 geliefert werden. Für eine leere Liste von Listen soll die Ausnahme
Empty geworfen werden.
Hinweis: Int.max : int * int → int liefert die größere zweier Zahlen.
Lösung 4.27:
load " Int "
fun greater ( ys , ( max , curpos , maxpos )) =
let
val curmax = foldl Int . max 0 ys
in
if curmax > max then ( curmax , curpos + 1 , curpos )
else ( max , curpos + 1 , maxpos )
end
fun thegreatest nil = raise Empty
| thegreatest xs = #3( foldl greater (0 , 0 , ∼1) xs )
7
Aufgabe 4.28
Schreiben Sie eine Prozedur power: α list → α list list, die ähnlich zur Potenzmenge die Liste aller
Teillisten einer Eingabeliste liefert. Für [1,2,2] soll die Ausgabeliste folgende Listen enthalten:
[], [1], [2], [2], [1,2], [1,2], [2,2], [1,2,2].
Lösung 4.28:
fun power nil = [ nil ]
| power ( x :: xr ) = map ( fn xs ⇒ x :: xs ) ( power xr ) @ power xr
4
Programmierung – eine Einführung in die Informatik mit Dieter Schlau
Aufgabe 4.29 (Einmal Falten, bitte!)
Schreiben Sie eine nichtrekursive Prozedur magic : real list → real list mittels einer Benutzung von
Faltung, die eine Liste von Werten nimmt und eine Liste der Differenzen dieser Werte zum Durchschnittswert
der Liste zurückgibt. Es soll also gelten: magic [1.0,2.0,3.0] = [∼1.0,0.0,1.0]. Benutzen Sie keine der
bekannten Listenprozeduren (außer genau einmal Faltung). Sie dürfen Real.fromInt verwenden.
Lösung 4.29:
load " Real "
fun magic xs = let
val (b ,s , c ) = foldr ( fn (e , (b ,s , c )) ⇒
( fn m ⇒ e − m :: b m , s + e , c + 1))
(( fn m ⇒ nil ) , 0.0 , 0) xs
in
( b ( s / Real . fromInt c ))
end
8
Herunterladen