Haskell-Lückentextaufgaben, alle von der Art
Ersetze undefined durch einen Ausdruck,
so daß der Wert von test gleich True ist.
Beispiel: Aufgabe:
test = let { x = undefined :: Int } in x * x == 9
Lösung:
test = let { x = 3 :: Int } in x * x == 9
nach möglichst kleiner Quelltextgröße (die angegebene Zahl ist die Anzahl der Knoten des Syntaxbaums der Lösung minus die der Vorgabe), im Beispiel also 0 (sowohl 3
als auch undefined
sind je ein Knoten).
Aufgaben gibt es hier: http://kernkraft.imn.htwk-leipzig.de/mind-the-gap/cgi-bin/Super.cgi
Jeder Hal-Teilnehmer kann teilnehmen. Die Hal-Anmeldenummer hat die Form hal9-1129314150-82 Matrikelnummer: die ersten fünf Ziffern (11293), Passwort: die nächsten 5 Ziffern (14150).
Dann Login (NICHT Enter), dann Vorlesung/Übungsgruppe wählen (es gibt nur eine), dann nochmal auf Vorlesung clicken, dann sieht man die Aufgaben.
Highscore-Auswertung am Nachmittag. Es ist ein virtuelles Tutorium, also gibt es auch nur virtuelle Preise.
test
wird er jedoch eine Exception erhalten).test
aus und das darf der Student nicht ändern)Bsp: multiply-peano-numbers. Testfälle werden dabei explizit angegeben.
test = and
[ plus (S (S Z)) Z == S (S Z)
, plus (S (S Z)) (S (S (S Z))) == S(S(S(S(S Z))))
, times (S (S Z)) Z == Z
, times (S (S Z)) (S (S (S Z))) == S(S(S(S(S (S Z)))))
]
das reicht oft schon aus (in Zusammenhang mit einem strengen Quelltextschema)
plus :: N -> N -> N
plus x y = case x of
Z -> undefined
S x' -> undefined
times :: N -> N -> N
times x y = case x of
Z -> undefined
S x' -> plus undefined undefined
man könnte hier einen Cheat versuchen: die ersten beiden Tests besteht man auch mit
plus x y = case x of
Z -> undefined
S x' -> case y of Z -> S (S Z) ; _ -> S(S(S(S(S Z))))
aber es wird schwierig, ein dazu passendes times
zu bauen. (Können die Leute gern probieren.)
durch Smallcheck (Bsp: append-reverse), Bsp:
reverse :: List a -> List a
reverse' :: List a -> List a
spec4 = \ ( xs :: List Bool ) ->
reverse xs == reverse' xs
Hierbei ist der Typ im Test eingeschränkt (List Bool), aber der Student muß trotzdem polymorph imlementieren (List a).
Smallcheck hat nicht genau die Testtreiber, die ich brauche, deswegen steht immer noch etwas Hilfscode in der Aufgabe
-- | first f failures from t testcases for property p
failures f t p = take f ...
Der Student sollte trotzdem in ghci einfach folgendes ausführen:
smallCheck 3 spec4
(Bsp: append-reverse)
hier ist das append
korrekt vorgegeben und die Spezifikation von reverse lautet
spec1 = \ ( xs :: List Bool) ->
reverse (reverse xs) == xs
spec2 = \ ( xs :: List Bool, ys ) ->
reverse (append xs ys) == append (reverse ys) (reverse xs)
Interessant ist die Frage, ob dadurch bereits das “richtige” reverse erzwungen wird - sowie, ob die Einschränkung des Typs im Test wirklich nichts schadet.
(Bsp: peano-symdiff) hier ist die Spec. wirklich eindeutig.
Ist das eine gute Aufgabenstellung?
test :: Bool
test = null $ failures 10 1000 $ \ (f, a, xs) ->
foldr f (a :: Bool) (xs :: [Bool])
== foldl undefined undefined (reverse xs)
Die beabsichtigter Lösung ist foldl (flip f) a xs aber da kann man mogeln und das foldl umgehen (darauf muß man aber auch erstmal kommen):
test = null $ failures 10 1000 $ \ (f, a, xs) ->
foldr f (a :: Bool) (xs :: [Bool])
== foldl ( \ _ _ -> foldr f a xs) a (reverse xs)
Bsp: check-AVL-balance-via-fold
die Funktion balanced
kann nicht durch fold definiert werden (weil es nicht ausreicht, in der Wurzel zu wissen, on linkes und rechtes Kind balanciert sind).
Man führt eine Hilfsfunktion ein, die berechnet ein Paar, dessen zweite Komponente enthält das gewüschte Bit und die erste Komponente liefert die Hilfsinformation, so daß man insgesamt ein fold bauen kann.
balanced :: Tree a -> Bool
balanced t = snd
$ fold ( \ k -> (0,True) )
undefined
$ t
In vielen Haskell-Programmen werden Monaden benutzt, dann muß ja diese Aufgabe leicht sein: find-the-monoid.
Dort sieht man auch, wie Smallcheck natürliche Zahlen generiert.