musterlösung 5

Werbung
Algorithmen und Programmierung
5. Aufgabenblatt
Aufgabe 4.5
a) Codieren und Decodieren mit Caesar und Uncaesar:
-- einfaches Codieren
caesar :: Int -> String -> String
caesar n xs = map ( chr.flip mod 255. (+) n. ord ) xs
-- einfaches Decodieren
uncaesar :: Int -> String -> String
uncaesar n xs = caesar (-n) xs
Testläufe:
*Programme> uncaesar 10 (caesar 10 "abcdefg")
"abcdefg"
*Programme> uncaesar 100 (caesar 100 "abcdefg")
"abcdefg"
*Programme> caesar 160 "abcdefg"
"\STX\ETX\EOT\ENQ\ACK\a\b"
Der letzte Testlauf zeigt das Problem, dass die Zeichen nach der Codierung
zwischen 0 und 31 liegen und nicht mehr druckbar sind.
b) Alle Zeichen c mit 0 <= ord c < 32 bleiben unverändert.
Damit der Text dekodierbar bleibt, darf kein Zeichen c mit ord c >= 32 auf ein
Zeichen mit Ascii-Wert zwischen 0 und 31 abgebildet werden.
Quellcode:
-- kleinstes ( bzgl. des ASCII Wertes ) druckbares Zeichen
lowChar = ord ' '
-- Codieren des druckbaren Bereichs
caesar' n
= map (chr.encryptC n)
-- Hilfsfunktion, die das Zeichen zwischen 32 und 255 abbildet
encryptC n c
|ord c < lowChar
= ord c
|otherwise
= shift (n+ord c)
where shift k = (k-lowChar) `mod` (256-lowChar) + lowChar
-- Decodieren des druckbaren Bereichs
uncaesar' n = caesar' (-n)
Testläufe:
*Programme> caesar' 1 [chr 255]
" "
*Programme> uncaesar' (1) " "
"\255"
1
*Programme> caesar' 160 "abcdefg"
"!\"#$%&'"
*Programme> uncaesar' 160 (caesar' 160 "abcdefg")
"abcdefg"
Aufgabe 5.1
Realisierung eines n-Bit-Addierwerks aus n Volladdierern
data Bit = O | I
deriving Show
-- Logisches ODER
bOR :: Bit -> Bit -> Bit
bOR O O = O
bOR _ _ = I
-- Logisches UND
bAND :: Bit -> Bit -> Bit
bAND I I = I
bAND _ _ = O
-- Logisches XOR
bXOR :: Bit -> Bit -> Bit
bXOR O O = O
bXOR I I = O
bXOR _ _ = I
-- Halbaddierer
-- (Summe, Übertrag)
bHalfAdder :: Bit -> Bit -> (Bit, Bit)
bHalfAdder x y = (bXOR x y, bAND x y)
-- Volladdierer
-- (Summe, Übertrag)
bVollAdder :: Bit -> Bit -> Bit -> (Bit, Bit)
bVollAdder x y cin = (s2,cout)
where
(s,c) = bHalfAdder x y
(s2,c2) = bHalfAdder s cin
cout = bOR c2 c
-- Addierwerk
bAdder xs ys = reverse ( bAdderH (reverse xs) (reverse ys) O )
-- Endrekursiver Addierer
-- 3ter Parameter a ist der Akkumulator mit dem Übertrag
bAdderH :: [Bit] -> [Bit] -> Bit -> [Bit]
bAdderH [] [] a = [a]
-- letzen Übertrag speichern
bAdderH (x:xs) (y:ys) cin = sout:(bAdderH xs ys cout)
where
( sout , cout ) = bVollAdder x y cin
Testlauf
*Programme> bAdder [I,I,I,I] [O,O,O,O]
[O,I,I,I,I]
*Programme> bAdder [I,I,I,I] [I,I,I,I]
2
[I,I,I,I,O]
*Programme> bAdder [I,I,I,I] [O,O,O,I]
[I,O,O,O,O]
Aufgabe 5.2
a) foo [] = []
foo [x:xs] = bar x : foo xs
foo ist falsch definiert. Es gibt 2 korrekte Varianten:
foo [] = []
foo [x:xs] = bar x : foo [xs]
oder
foo [] = []
foo (x:xs) = bar x : foo xs
Der Rückgabetyp von foo ist abhängig von bar
b) [(1:(2:[]))]
Korrekt. Liste vom Typ [Int]
*Programme> [(1:(2:[]))]
[[1,2]]
c)
[1]:[2,3]
Falsch. Der Listenkonstruktor ist nicht für [Int] -> [Int] definiert.
*Programme> :t (:)
(:) :: a -> [a] -> [a]
d) ['a', chr 98, 'c']
Korrekt.
chr98 liefert den Char 'b'
Typ ist String oder [Char]
*Programme> ['a', chr 98, 'c']
"abc"
e)
['a','98','c']
Falsch. Chars in Haskell bestehen aus maximal einem Zeichen. '98' ist somit
kein gültiger Char.
*Programme> ['a','98','c']
<interactive>:1: lexical error in string/character literal
3
f)
[[],[]]
Korrekt. Liste von Listen.
Typ ist abhängig vom Kontext [[a]]
*Programme> [[],[]]
[[],[]]
g) [['1'], "Hallo"]
Korrekt. Liste von Strings
Typ ist [String]
*Programme> [['1'], "Hallo"]
["1","Hallo"]
h) ([1,2,3],"Foo")
Korrekt. Tupel mit 2 Elementen
Typ ist ([Int], String)
*Programme> ([1,2,3],"Foo")
([1,2,3],"Foo")
i)
map f . map g
Korrekt. Funktionsapplikation von g unf f auf eine Liste.
Typ [a] -> [b] abhängig von f ung g
j)
map map
Korrekt. map wendet map auf eine Liste von Funktionen an und liefert eine
Liste mit map-Funktionen angewandt auf jeweils eine Funktion aus der
Funktionsliste.
(map map) [f,..,h] = [map f, ... , map h]
Man kann mit der Liste arbeiten, indem man z.B. eine der Funktionen mit (!!)
auswählt.
Typ: (map map) :: [a->b] -> [[a]->[b]]
*Programme> (!!) ((map map) [(^2),(^3)]) 0 [1..10]
[1,4,9,16,25,36,49,64,81,100]
*Programme> (!!) ((map map) [(^2),(^3)]) 1 [1..10]
[1,8,27,64,125,216,343,512,729,1000]
k) map . map
Korrekt.
4
Allgemein gilt für den (.)-Operator:
(.) f g x= f (g x)
Analog mit map map:
(map.map) f xs = ((map.map) f) xs = map (map f) xs
D.h. es wird map mit einer Funktion f auf eine Liste von Listen xs gemappt.
Typ: (map . map) :: (a->b) -> [[a]] -> [[b]]
*Programme> (map . map) ord ["FU","Berlin"]
[[70,85],[66,101,114,108,105,110]]
l)
map (map quadrat) [[1,2], [3,4,5]]
Korrekt. Funktionsweise analog zu map.map
Typ: [[Int]]
*Programme> map (map (^2)) [[1,2], [3,4,5]]
[[1,4],[9,16,25]]
m) (4), (5) und (8) sind korrekt
(4) (.) :: (b -> c) -> (a -> b) -> (a -> c)
(5) (.) :: (c -> a) -> (b -> c) -> b -> a
(8) (.) :: (a -> b) -> (c -> a) -> (c -> b)
*Programme> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
Aufgabe 5.3
a) Join
join xs ys = [(x,y,z)| (x,y)<-xs, (x',z)<-ys, x'==x ]
Testlauf:
*Programme> join [(1,2),(1,3)] [(1,1),(2,2)]
[(1,2,1),(1,3,1)]
b) Truthtab
-- Permutationen der Wahrheitswerte
args = [(x,y) | x <- [False,True], y <- [False, True]]
-- Wahrheitstabelle
wTab :: (String, (Bool -> Bool -> Bool)) -> (String,
[(Bool,Bool,Bool)])
wTab (name,op) = (name, map op' args)
where op' (x,y) = (x,y, op x y)
5
-- Mappt eine Liste von Boolschen Funktionen auf die
Permutation der Wahrheitswerte
truthTabs :: [(String, Bool -> Bool -> Bool)] -> [(String,
[(Bool, Bool, Bool)])]
truthTabs xs = map wTab xs
Testlauf:
*Programme> truthTabs [("and",(&&)),("or",(||))]
[("and",[(False,False,False),(False,True,False),(True,False,Fal
se),(True,True,True)]),("or",[(False,False,False),(False,True,T
rue),(True,False,True),(True,True,True)])]
Aufgabe 5.4
a) [ x | x <- xs, y <- ys ]
gibt jedes Element x aus xs y mal hintereinander aus.
*Programme> [ x | x <- [1..5], y <- [1..5] ]
[1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5]
[ x | y <- ys, x <- xs ]
gibt y mal die Folge aller Elemente aus xs aus.
*Programme> [ x | y <- [1..5], x <- [1..5] ]
[1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
Die beiden sind identisch, falls die die Länge von ys 1 oder 0 ist und/oder xs
nur gleiche Elemente enthält.
*Programme> [ x
[1,1,1,1], y <True
*Programme> [ x
[1,1,1,1], y <True
| y <- [1..5], x <- [1,1,1,1] ] == [ x | x <[1..5] ]
| y <- [1..1], x <- [1,1,1,1] ] == [ x | x <[1..1] ]
b) Alternative Definition von filter mit Hilfe von concat und map
filternew p = concat . map bx
where
bx x | p x
= [x]
| otherwise = []
Testlauf:
*Programme> filternew (>0) [-1,1]
[1]
c)
Alle Tripel mit a2 + b2 = c2
pythagoras = [(x,y,z) |
x <- [1..sqrt(999)],
y <- [1..sqrt(999)],
z <- [1..sqrt(999)],
x*x+y*y==z*z]
6
Testlauf:
*Programme> pythagoras
[(3,4,5),(4,3,5),(5,12,13),(6,8,10),(7,24,25),(8,6,10),(8,15,17
),(9,12,15),(9,40,41),(10,24,26),(11,60,61),(12,5,13),(12,9,15)
,(12,16,20),(12,35,37),(13,84,85),(14,48,50),(15,8,17),(15,20,2
5),(15,36,39),(16,12,20),(16,30,34),(16,63,65),(18,24,30),(18,8
0,82),(20,15,25),(20,21,29),(20,48,52),(21,20,29),(21,28,35),(2
1,72,75),(24,7,25),(24,10,26),(24,18,30),(24,32,40),(24,45,51),
(24,70,74),(25,60,65),(27,36,45),(28,21,35),(28,45,53),(28,96,1
00),(30,16,34),(30,40,50),(30,72,78),(32,24,40),(32,60,68),(33,
44,55),(33,56,65),(35,12,37),(35,84,91),(36,15,39),(36,27,45),(
36,48,60),(36,77,85),(39,52,65),(39,80,89),(40,9,41),(40,30,50)
,(40,42,58),(40,75,85),(42,40,58),(42,56,70),(44,33,55),(45,24,
51),(45,28,53),(45,60,75),(48,14,50),(48,20,52),(48,36,60),(48,
55,73),(48,64,80),(51,68,85),(52,39,65),(54,72,90),(55,48,73),(
56,33,65),(56,42,70),(57,76,95),(60,11,61),(60,25,65),(60,32,68
),(60,45,75),(60,63,87),(60,80,100),(63,16,65),(63,60,87),(64,4
8,80),(65,72,97),(68,51,85),(70,24,74),(72,21,75),(72,30,78),(7
2,54,90),(72,65,97),(75,40,85),(76,57,95),(77,36,85),...]
Patrick Schäfer et al.
7
Herunterladen