Nada Tentamensdag 2002-aug-20 Tentamen i Funktionell Programmering Skrivtid 5 h Antalet uppgifter : 5 ( 26p +22p + 14p +26p + 12 p= 100 p ) Lärare, jourhavande lärare : Leif Kusoffsky ------------------------------------------------------------------------------------------------------------------ Tillåtna hjälpmedel: Hudak : The Haskell School of Expression Jones et al : Report on the Programming Language Haskell 98 (Häfte + appendix) övrigt material i kursbunten (Hugs-manualen, Bvs: Datastukturer i Haskell, "Vissa laborationer..") Mina tryckta föreläsningsanteckningar. ----------------------------------------------------------------------------------------------------------------- I alla deluppgifterna, skriv typen för de identifierare du definierar. 1 Bokens (Hudak) uppgift 5.7 sid 73. Define a function that adds "pointwise" the elements of a list of pairs. For example: addpairspointwise [(1, 2),(3, 4),(5, 6)] blir (9,12) a) Vilken typ har addpairspointwise? (Helst så generell som möjligt, "add" är Haskells +. b) Skriv addpairspointwise utan att använda högre ordningens funktioner (och inte som i uppgift e) c) Skriv addpairspointwise med foldr. d) Skriv addpairspointwise med foldl. e) Skriv addpairspointwise med hjälpfunktion med "accumulering i parameter". f) Vilka av lösningarna är minneseffektiva, dvs deluttrycken under reduktionerna är ej O(n) där n är listans längd? 26p) 2 Definiera i Haskell en DT (datatyp) Vector2 (vektorer i planet) med följande operationer: Vector2, -- datatyp för vektorer i planet Vector2, -- Double-> Double->Vector2 Konstuktorfunktion för vektor read, -- String -> Vector2 inläsning på formen Vector2 1.0 2.0 read1, -- (Double, Double) -> Vector2 -- för inläsning på formen read1 (1.0, 2.0) show, -- Vector2 -> String utskrift på formen Vector2 1.0 2.0 show1, -- Vector2 -> (Double, Double) för utskrift på formen (1.0, 2.0) (==), -- Vector2 -> Vector2 -> Bool lika med (/=), -- Vector2 -> Vector2 -> Bool ej lika med add, -- Vector2 -> Vector2 -> Vector2 vektoradditon sub, -- Vector2 -> Vector2 -> Vector2 vektorsubtraktion neg, -- Vector2 -> Vector2 negering lengthv2, -- Vector2 -> Double vektorlängd ( absolutbelopp) o, -- Vector2 -> Vector2 -> Double skalärprodukt -- Tillägsuppgift (+), -- överlagrad operator för add (-), -- överlagrad operator för sub (*), -- ska ge error negate -- överlagrad funktion för negate
Exempel på körningar : Vector2> Vector2 1 (-3)/= Vector2 4 4 True Vector2> Vector2 1 (-3)+ Vector2 4 2 Vector2 5.0 (-1.0) Vector2> Vector2 1 (-3) add Vector2 4 2 Vector2 5.0 (-1.0) Vector2> show1 (read1 (1, -3) + read1 (4, 2)) (5.0,-1.0) Vector2> read1 (1, -2) o read1 (-3, 4) -11.0 22p) 3 a) Definera en typklass Vector med operationerna i Num (abs och frominteger impementeras med error ) och som dessutom har operationerna o (skalärprodukt) och absv (längd för vectorer). b) Hur gör man för att Vector2 i uppgift 2 skall tillhöra typklassen Vector? 14p) I alla uppgifter och deluppgifterna, skriv typen för de identifierare du definierar
4. a) Skriv i FAL (Hudak kap 15, ditt program kan importera det FAL som användes i laborationen och använder mm istället för tum) ett program Hunt som gör att en blå ellips kan styras i ett grafiskt fönster. Elippsens läge ges av s = ( a dt ) dt + s0 10p) där fet stil betyder vektorer i planet och båda komponeterna. integrering av vektorer i planet, dvs integering av Elippsen acceleration a= (accx, accy) är från början a= (0.0, 0.0), men varje gång man trycker på tangenten i ökar accx med 1.0, accy oförandrad varje gång man trycker på tangenten m minskar accx med 1.0, accy oförandrad varje gång man trycker på tangenten k ökar accy med 1.0, accx oförandrad varje gång man trycker på tangenten i minskar accy med 1.0, accx oförandrad andra tangentryckningar accy oförandrad,accx oförandrad Tips: Du kan ha glädje av Hudaks program color3 och color 4 på sid 212. Svaret kan ingå i svaret på b) eller c). b) Modifiera lösningen i a) så det grafisk fönstret även visar en gul ellips som rörs sig analogt med den blå ellipsen men styrs av e, x, s, d. Märk att tangenterna bildar följande mönster: e i s d j k x m Styr gul ellips Styr blå ellips Programmet kan nu användas som ett spel för två personer som styr varsin ellips, t ex ett samarbetspel där spelarna försöker få sina ellipser att mötas eller ett spel där blå ellips jagar gul ellips. Tips: Svaret kan ingå i svaret på c). c) Modifera lösningen i b) så att när ellipserna är mindre än 5 mm från varandra de"parkeras" nära varandra i det grafiska fönstrets mitt och ej längre rör sig. 26p) Bifogas : Översikt av FAL.
5. a) Alla traditionella grafiska interaktiva program som växelvis ritar på skärmen och reagerar på klickningar fungerar på så sätt att programmet befinner sig i ett startillstånd av godtycklig typ a, därefter sker detta: En första gång och sedan gång på gång så länge programmet skall fortsätta: rita på skärmen Vänta på klickningen, man får koordinater i "pixels", origo upptill till vänster, av typ (i, j) :: Input, type Input = (Int, Int) kör en funktion f :: a {-status-} -> Input -> (a, [Graphic]) som retunerar ett par (ny status av typ a, nya bilder av typ [Graphic]) ) Detta kan programmeras en gång för alla med funktionera main, makegraphicinteractive, och loop : module GraphicInteract where -- finns på /info/progp02/haskell/graphicinteract.hs import SOEGraphics makegraphicinteractive :: a -> String {- föntertittel-} -> (Int, Int) {- fönsterstorlek -}->[Graphic] {-startbilder-} -> (a -> (Int,Int) -> (a,[graphic])) {- förändringsfunktion-}-> IO () makegraphicinteractive startstatus title (isize, jsize) firstgraphs f = rungraphics (do w <- openwindow title (isize, jsize) loop w startstatus firstgraphs f ) Skriv funktionen loop :: Window -> a -> [Graphic] -> (a -> (Int,Int) -> (a,[graphic])) -> IO b (Min lösning på är 5 rader.) Raderna i makegraphicinteractive och loop är all "IO Monad"-programmering som behövs. Genom att använda makegraphicinteractive kvarstår bara att definiera argumenten som motsvarar parametern f, startillståndet och de första bilderna (en bild har typen Graphic) som är vanliga "monadfria" funktionella program/värden, så får man ett grafiskt växelvis interaktiva program. b) Skulle makegraphicinteractive kunna användas för att programmera schack-labben? Labyrintlabben? 12p)
Förfrågan: Kan du tänka dig att vara labbassistent under läsperiod 1 i kursen programmeringsparadigemer i D2? Kryssa gärna i ett eller båda alternativen. (Naturligtvis ej bindande) O I Haskelldelen av kursen O I Prologdelen av kursen Hur kan jag kontakta dig (tex e-pos, tel ):
Förslag till svar tentamen i Funktionell Programmering 2D1370 2002-aug-20 addpairspointwise ::(Num a, Num b) => [(a,b)] -> (a,b) -- 1 a addpairspointwise [] = (0, 0) -- b addpairspointwise ((x, y) : xys ) = (x+xs, y+ys) where (xs, ys) = addpairspointwise xys addpairspointwise = foldr (\(x, y) -> \(xs, ys) -> (x+xs, y+ys)) (0, 0) -- addpairspointwise = foldl (\(xs, ys) -> \(x, y) -> (xs+x, ys+y)) (0, 0) -- c d addpairspointwise xys = app xys (0,0) -- e where app :: (Num a, Num b) => [(a,b)] -> (a,b) -> (a,b) app ((x, y) : xys) (xs, ys) = app xys (xs+x, ys+y) app [] (xs, ys) = (xs, ys) d) och e) använder uttryck som ej växer med listans längd -- f -- 2 module Vector2 ( Vector2, -- datatyp för vektorer i planet Vector2, -- Double-> Double->Vector2 Konstuktorfunktion för vektor read, -- String -> Vector2 inläsning på formen Vector2 1.0 2.0 read1, -- (Double, Double) -> Vector2 -- för inläsning på formen read1 (1.0, 2.0) show, -- Vector2 -> String utskrift på formen Vector2 1.0 2.0 show1, -- Vector2 -> (Double, Double) för utskrift på formen (1.0, 2.0) (==), -- Vector2 -> Vector2 -> Bool lika med (/=), -- Vector2 -> Vector2 -> Bool ej lika med add, -- Vector2 -> Vector2 -> Vector2 vektoradditon sub, -- Vector2 -> Vector2 -> Vector2 vektorsubtraktion neg, -- Vector2 -> Vector2 negering lengthv2, -- Vector2 -> Double vektorlängd ( absolutbelopp) o, -- Vector2 -> Vector2 -> Double skalärprodukt -- Tillägsuppgift (+), -- överlagrad operator för add (-), -- överlagrad operator för sub (*), -- ska ge error negate -- överlagrad funktion för negate ) where data Vector2 = Vector2 Double Double deriving (Eq, Show, Read) add :: Vector2 -> Vector2 ->Vector2 add (Vector2 x1 y1) (Vector2 x2 y2) = Vector2 (x1+x2) (y1+y2) sub:: Vector2 -> Vector2 ->Vector2 sub v1 v2 = add v1 (neg v2) neg :: Vector2 -> Vector2 neg (Vector2 x y) = Vector2 (-x) (-y) lengthv2 :: Vector2 -> Double lengthv2 (Vector2 x y) = sqrt (x*x + y*y) read1 :: (Double, Double) -> Vector2 read1 (x, y) = Vector2 x y show1 :: Vector2 -> (Double, Double) show1 (Vector2 x y) = (x, y)
o :: Vector2 -> Vector2 -> Double o (Vector2 x1 y1) (Vector2 x2 y2) = (x1*x2 + y1*y2) instance Num Vector2 where (+) = add (*) = error "No * on vectors" negate = neg abs = error "abs" frominteger i = error "frominteger" class Num a => Vector a where o :: a -> a -> Double absv :: a -> Double -- 3 a -- Skriv i filenvector2.hs -- b instance Vector Vector2 where o (Vector2 x1 y1) (Vector2 x2 y2) = (x1*x2 + y1*y2) absv = lengthv2 -- o får inte definieras på annat ställe i filen, dvs tas bort i svaret på 2. module Hunt where -- 4 import Picture(Picture, Region, containsr) import Fal main :: IO() main = test ( (ell1) over (ell2) ) ellb :: Behavior Region ellb = ell 3 4 ell1, ell2 :: Behavior Picture ell1 = paint yellow ((translate pos1 ellb) untilb (smash ->> translate (0.0, 0.0) ellb )) ell2 = paint blue ((translate pos2 ellb) untilb (smash ->> translate (5.0, 0.0) ellb )) pos1, pos2 :: (Behavior Float,Behavior Float) pos1 = integral2 (integral2 (accx1, accy1)) addpairb (0.0, 40.0) pos2 = integral2 (integral2 (accx2, accy2)) addpairb (0.0, -40.0) accx1, accy1, accx2, accy2 :: Behavior Float accx1 = (0.0 switch (key snapshot accx1 =>> \(c, old) -> case c of s -> lift0 old - 1.0 d -> lift0 old + 1.0 _ -> lift0 old )) accy1 = (0.0 switch (key snapshot accy1 =>> \(c, old) -> case c of x -> lift0 old - 1.0 e -> lift0 old + 1.0 _ -> lift0 old )) accx2 = (0.0 switch (key snapshot accx2 =>> \(c, old) -> case c of j -> lift0 old - 1.0 k -> lift0 old + 1.0 _ -> lift0 old ))
accy2 = (0.0 switch (key snapshot accy2 =>> \(c, old) -> case c of m -> lift0 old - 1.0 i -> lift0 old + 1.0 _ -> lift0 old )) integral2 :: (Behavior Float, Behavior Float) -> (Behavior Float, Behavior Float) integral2 (bx, by) = (integral bx, integral by) addpairb :: (Num a, Num b) => (b,a) -> (b,a) -> (b,a) addpairb (a1, b1) (a2, b2) = (a1+a2, b1+ b2) hit :: (Behavior Float, Behavior Float) -> (Behavior Float, Behavior Float) -> Behavior Bool hit (mx, my) (sx,sy) = (abs(mx-sx) <*5) &&*(abs(my-sy)<*5) smash :: Event () smash = when (hit (pos1) (pos2)) -- 5 loop w status graphs f = do sequence_ (map (drawinwindow w) graphs) (x, y) <- getlbp w let (status1, graph1s ) = f status (x,y) loop w status1 graph1s f -- Schacklabben ja, men inte labyrintlabben, som ju är äkta reaktiv ("realtid") -- och inte växelvis interaktiv.