1 - Niemand mag: [ ] Java; [ ] Prolog; [ ] Haskell; [ ] Klausuren schreiben Java 1) 2) 3) 4) 5) e a, c keine Antwort ist korrekt a, d a, c Prolog 6) 7) 8) 9) 10) d a, b, d, e a d a, b, c Haskell 11) 12) 13) 14) 15) a keine Antwort ist korrekt b, d, e a, b, e b, c, d 2 - Hobby: Constraint- und Metaprogrammierung :- use_module(library(clpfd)). xkcd(Xs) :Xs = [Fruits,Fries,Salad,Wings,Sticks,Plate], Xs ins 0..10, Total = 1505, Fruits * 215 + Fries * 275 + Salad * 335 + Wings * 355 + Sticks * 420 + Plate * 580 #= Total, labeling([],Xs). /* ?- xkcd([Fruits,Fries,Salad,Wings,Sticks,Plate]). Fries = Salad, Salad = Sticks, Sticks = 0, Fruits = Plate, Plate = 1, Wings = 2; Fries = Plate, Plate = Salad, Salad = Sticks, Sticks = Wings, Wings = 0, Fruits = 7. */ proveList(true,[]) :- !. proveList((G1,G2),Ls) :- 1 !, proveList(G1,Ls1), proveList(G2,Ls2), append(Ls1,Ls2,Ls). proveList(L,[L|Ls]) :- clause(L,G), proveList(G,Ls). 3 - Refactoring ggT :: Integer -> Integer -> Integer ggT a b = if b==0 then a else ggT b (mod a b) ggT' a 0 = a ggT' a b = ggT b (mod a b) isPrefixOf :: Eq a => [a] -> [a] -> Bool isPrefixOf x (y:ys) = if length x == 0 then True else isPrefixOf x (y:ys) isPrefixOf x (y:ys) = if head x == y then isPrefixOf (tail x) ys else False isPrefixOf' [] _ = True isPrefixOf' (x:xs) (y:ys) = x == y && isPrefixOf xs ys ----catJusts :: [Maybe a] -> [a] catJusts [] = [] catJusts (m:ms) = case m of Just x -> x : catJusts ms Nothing -> catJusts ms catJusts' ms = [ x | Just x <- ms ] catJusts'' ms = foldr (\m acc -> maybe id (\v -> (v:)) m acc) [] ms allPairs :: [a] -> [b] -> [(a,b)] allPairs xs ys = concatMap (\x -> map (\y -> (x,y)) ys) xs allPairs' xs ys = [ (x,y) | x <- xs, y <- ys ] ----fa :: Ord a => [a] -> a -> [a] fa [] y = [y] fa (x:xs) y = case y <= x of True -> y : x : xs False -> x : fa xs y fb :: (a -> Bool) -> b -> b -> a -> b fb a b c d = if a d then b else c fc :: a -> b -> a fc x y = x 2 fd :: [a] -> (b -> a -> b) -> b -> b fd [] g z = z fd (x:xs) g z = (fd xs g (g z x)) fe :: (a -> b) -> b -> Maybe a -> b fe x y Nothing = y fe x y (Just v) = x v 4 - Fahrkarten, bitte! data Ticket = TrainTicket City City TrainClass | BusTicket City City deriving Eq from :: Ticket -> City from (TrainTicket start _ _) = start from (BusTicket start _ ) = start to :: Ticket -> City to (TrainTicket _ dest _) = dest to (BusTicket _ dest ) = dest data TrainClass = First | Second deriving (Eq,Show) type Journey = [Ticket] data City = Berlin | Bonn | Frankfurt | Freiburg deriving (Eq,Show) example1 :: Ticket example1 = TrainTicket Hamburg Kiel First example2 :: Ticket example2 = BusTicket Freiburg Frankfurt valid :: Journey -> Bool valid [ ] = True valid [t1] = True valid (t1:t2:ts) = to t1 == from t2 && valid (t2:ts) -- bonus point with foldr -- valid (t:ts) = -snd (foldr (\t2 (t1,acc) -> (t2, acc && to t1 == from t2)) -(t,True) -ts) instance Show Ticket where show (TrainTicket start dest cls) = "Train (" ++ show cls ++ "): " ++ show start ++ " ~> " ++ show dest show (BusTicket start dest) = "Bus: " ++ show start 3 ++ " ~> " ++ show dest 5 - Nichtdeterministisches Sortieren 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ?- swap([4,3,2],Xs). (*) |- { A1 -> 4, B1 -> 3, Xs -> [3,4,2] } ?- 3 < 4. Ausgabe: Xs = [3,4,2] Backtracking, weiter mit Regel 2 bei (*) |- { A1 -> 4, L1 -> [3,2], Xs -> [4 | N1] } ?- swap ([3,2], N1) (**) |- { A2 -> 3, B2 -> 2, L2 -> [], N1 -> [2,3 | []] } ?- 2 < 3. Ausgabe: Xs = [4,2,3] Backtracking, weiter mit Regel 2 bei (**) |- { A2 -> 3, L2 -> [2], N1 -> [3 | N2] } ?- swap([2], N2). # 2te Regel, da 1te nicht anwendbar |- { A3 -> 2, L3 -> [], N2 -> [2 | N3] } ?- swap([],N2). Fehlschlag, keine Regel passt -- keine weitere Regel anwendbar bubble(L, R) :- swap(L, N), !, bubble(N, R). bubble(L, L). Nachdem einmal swap erfolgreich durchgeführt wurde, kommt der Cut-Operator zum Tragen, so dass keine zweites swap durchgeführt wird. Die Restliste wird dann entsprechend weiter sortiert; für alle weiteren swapRelationen gilt wieder, dass nur der erste Pfad genommen wird. 6 - Die Philosophie ist eine Art Rache an der Wirklichkeit – Friedrich Nietzsche Implementierungsfehler 1. Fehler in Klasse Stick, Zeile 6 Beim Zurücklegen des Sticks fehlt die Anweisung isUsed = false, da der Stick sonst nie von einem anderen Philosophen genutzt werden kann. Richtig wäre also: public synchronized void put() { isUsed = false; notify(); } 2. Fehler in Klasse Stick, Zeile 11 Innerhalb des try-Blocks muss die Aufnahme eines Sticks mit Hilfe einer wait()-Anweisung blockiert werden, da der Stick bereits verwendet wird. Richtig wäre also: public synchronized void take() { while (isUsed) { try { wait(); } catch (InterruptedException e) {} } isUsed = true; } 4 3. Fehler in Klasse Philosopher, Zeile 29 - 33 Das wait auf dem linken Stick macht zum einen keinen Sinn, da das anschließende left.take() unter Umständen ebenfalls warten würde. Zum anderen ist bereits klar, dass der Stick nicht verwendet werden kann. Es muss einen alternativen Fall geben, der durch else eingeleitet wird. Richtig wäre also: right.take(); if (left.isUsed()) { right.put(); } else { left.take(); System.out.println("Eating."); } left.put(); right.put(); 5