I kapitel 15 gör Hudak för reaktiva animeringar detsamma som han i kapitel 13 gör för animeringar. Resultatet är en module Fal.

Storlek: px
Starta visningen från sidan:

Download "I kapitel 15 gör Hudak för reaktiva animeringar detsamma som han i kapitel 13 gör för animeringar. Resultatet är en module Fal."

Transkript

1 Föreläsning 9. Hudak avsnitt 15.1, kapitel 14 2D1370 Funktionell programmering v19 tisdag Programmering av reaktiv animering. Vad går kapitel 15 ut på? I kapitel 15 gör Hudak för reaktiva animeringar detsamma som han i kapitel 13 gör för animeringar. Resultatet är en module Fal. För labben har jag tillverkat en lite bantad variant som ligger på kthfal, se labhandledningen. Som vanligt gör han en ny typfamilj. Typfamiljen i kap 15 har samma namn som den i kapitel 13,. Dessa nya typer är krångliga att implementera, kommer senare, men vi kan tänka på dem som besläktade med typerna i kap 13 I kapitel 13 när vi sysslade med animeringar var typen a "förpackade funktioner" med typen Time -> a nu i kap 15 när vi sysslar med reaktiva animeringar är typen a "förpackade funktioner" T ex Time och användaråtgärder som musrörelser, tangenttryckningar mm -> a y b y b tid tid, användaråtgärder i kap 13 för animeringar i kap 15 för reaktiva animeringar

2 Användaråtgärderna är "händelser", men även beteenden kan utlösa händelser (t ex att bilden av ett föremål beter sig så att det hamnar utanför bilden av en spelplan o dylikt). I FAL finns ytterligaren en typfamilj Event a som också är "förpackade funktioner" med typen Time och användaråtgärder som musrörelser, tangenttryckningar mm -> Maybe a T ex lbp ("left button pushed ") och key ("tangent-tryckning" ) Just () lbpevent () Just () Just () keyevent Char Just a Just x Just r Nothing tid, användaråtgärder Nothing tid, användaråtgärder På liknade sätt som Hudak tidigare gjorde lyftfunktioner och nya funktioner för förvandla våra statiska Shape, Region och Picture till animerade Shape, Region och Pictureg i kapitel 13 gör Hudak i kapitel 15, men nu för för vår nya typfamlj som kan hantera reaktiva animeringar. Han tillverkar nya lyftfunktioner och tillverkar motsvarande funktioner som vi använt tidigare, ibland byter han namn, ibland inte, och ibland byter han betydelse lite grann. test, som motsvarar animateb,skriver han med hjälp av en funktion reactimate på liknande sätt som animateb skrivs med animate. reactimate förklaras och programmeras dock inte förrän i kapitel 17.

3 Float Float Ellipse ell Shape (Float, Float) Shape Shape Float, Float) shape Region Region Translate Red Magenta Yellow White red yellow translate Color Region over EmptyPic Color reg over empty Black Blue Green Cyan Picture Kap 10 Picture Picture String draw IO() animateb String IO() module Picture för att rita module Animation för att rita statiska bilder rörliga bilder kapitel <= 10 kapitel <= 13

4 Float ell rec Shape ( Float, Float) shape red, blue, yellow green white black translate Region Color paint over Picture test IO() Motsvarigheter i module Fal för att rita reaktiva animeringar kapitel 15. Märk t ex att ell (och rec som han också lyft nu) går direkt till Region. Shape spelar en underordnad roll i Fal. test (motsvarar animateb) skriver Faltest i fönstret där animeringen visas. Alla färger är också lyftade. paint motsvarar reg.

5 sqrt exp sin log cos tan asin acos atan sinh cosh tanh asinh acosh atanh negate abs signum integral + - * / pi time Float step a ->> b -> a =>>.. stepacccum Event a a mouse (, ) ell rec >* <* Bool &&* * when while Event (a->a) Event () Event Char lbp Event b key ( Float, Float) mm Event (Float, Float) red, blue, yellow green white black translate Region untilb switch Event ( a) pairb Color (a, b) fstb sndb paint over Picture snapshot_ snapshot withelem_ Event a Event (b, a) withelem test [a] IO() Komplettering med fler element i module Fal för att göra DSL FAL. Man kan behöva lyfta in ytterligare funktioner, t ex lyfte jag in not och containsr för att göra sista labben. Det viktigaste nya är dock allt som har med händelser att göra, typfamiljen Event. Vi kan nu studera avsnitt 15.1 i Hudak där vi programmerarar i vårt nya språk FAL.

6 Bokens inledande exempel Maybe () Just () lbp Event() Blue Color blue Color Nothing Detta är ett behavior dvs en "förpackad" funktion! Vänster knapp trycks tid,händelser ([Maybe UserAction, [Time]) Maybe (Behavoir Color) lbp->> blue Event(Behavoir Color) Just (blue) Nothing tid,händelser ([Maybe UserAction, [Time]) Vänster knapp trycks tid,händelser ([Maybe UserAction, [Time]) Red Color red Color tid,händelser ([Maybe UserAction, [Time]

7 color1 Behavoir Color color1 = red untilb (lbp->> blue) Color Blue circ Behavoir Region circle = translate (cos time, sin tim (ell ) Region Red ([Maybe UserAction, [Time]) Vänster knapp trycks tid,händelser ([Maybe UserAction, [Time]) tid,händelser ball1 Behavoir Picture ball1 = paint (red untilb (lbp->> blue) circ blå roterande cirkel Picture röd roterande cirkel Vänster knapp trycks ([Maybe UserAction], [Time]) tid,händelser

8 Några tentauppgifter. 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 Butterfly som gör att en gul rektangel 5 mm * 3mm, "fjärilen", rör sig i en Lissajou - figur dvs fjärilens position ges av s = (sx, sy ) = (50 sin 3t,30 cos7t) där t är tiden. Dessutom skall det på bilden finnas en "håv" (engelska net) som ritas som en ellips 5 mm * 10 mm och som följer musmarkörens röelser. 3p) b) Modifera lösningen i a) så när håven kommer inom 5 mm från fjärilen så fångas fjärilen och förblir i fortsättningen i håven. 3p) c) Modifera lösningen i b) så att man genom att trycka på vänster knapp på musen kan "släppa ut" fjärilen från håven så att den åter flyger fritt som i a). Om fjäriln inte är i håven när man trycker på knappen så flyger den förstås på som vanligt. 3p) d) Modifiera läsningen i a) så att "fjärilen fladdar", dvs så att den gula rektangeln varierar i storlek som funktion av tiden. 3p) module ButterflyC where -- 4 import Picture(Picture, Region, containsr) import Fal main IO() main = test (butterfly over net ) butterfly, net Picture net = paint red (translate mouse netb) netb Region netb = ell 5 10 butterflyb Region -- uppgift d -- butterflyb = rec (5*sin (10*time)) ( 3* cos (10*time)) butterflyb = rec 5 3 sx, sy Float sx = 50*sin (3*time) sy = 30 * cos(7*time) butterfly = paint yellow (translate (sx, sy) butterflyb) {- butterflyfree, butterflyinnet Picture -- uppgift b butterflyfree = paint yellow (translate (sx, sy) butterflyb) butterflyinnet = paint yellow (translate (mouse) butterflyb)

9 -} butterfly = butterflyfree untilb ( ( caught ->> butterflyinnet )) where (mx, my) = mouse caught Event () caught = when ((abs(mx-sx) <*5) &&*(abs(my-sy) <*5)) butterfly = butterflyfree switch ( -- uppgift c ( lbp ->> butterflyfree).. ( caught ->> butterflyinnet )) where (mx, my) = mouse caught Event () caught = when ((abs(mx-sx) <*5) &&*(abs(my-sy) <*5)) Från fiktiva tentan Skriv i FAL ett program för Pas de Deau, där två dansare följer musens rörelser a) Dansarna håller konstant avstånd b) med mus-klick och tangenttryckningar kan avståndet variera module PasDeDeux where import Picture(Picture, Region, containsr) import Fal main IO() main = test (woman over man ) woman, man Picture distb (Float, Float) dist1, dist2 ( Float, Float) dist1 = ( 10.0, 10.0) dist2 = ( 5.0, 50.0) {- distb = pairb d1x d1y where (d1x, d1y) = dist1 -} distb = dist1b switch ( ( lbp ->> dist2b).. ( key ->> dist1b) ) where (d1x, d1y) = dist1 (d2x, d2y) = dist2 dist1b = pairb d1x d1y dist2b = pairb d2x d2y womanb = ell 1 5 manb = rec 2 10 man = paint yellow (translate mouse manb) s (Float, Float) s = (pairb (lift2 (+) xx mx) (lift2 (+) yy my)) where (mx, my) = mouse (xx, yy) = (fstb distb, sndb distb) woman = paint white (translate dist1 (translate (fstb s, sndb s) womanb) )

10 Programmering med lat evaluering och strömmar. Kapitel 14. Innnan vi kan implementera FAL måste vi förstå en del om Haskells sätt att reducera uttryck, dvs Haskells lata evaluering, och om strömmar, "oändliga listor". Detta behandlas i kapitel 14, och en bra inledning är också början av "Datastrukturer i Haskell" som finns i kursbunten. Haskells sätta att evaluera uttryck möjligör ett sätt att programmera som är mycket kraftfullt i många situationer, men känns lite "magiskt" för den ovane. Några olika sätt att beräkna Fibonacchis tal. fib Integer -> Integer fib 0 = 1 fib 1 = 1 fib n = fib (n-1) + fib (n-2) -- kastastrof ineffektiv med until-- fördefinierad svansrekusiv funktion until (a -> Bool) -> (a -> a) -> a -> a until p f x p x = x otherwise = until p f (f x) fib Integer -> Integer fib 0 = 1 fib 1 = 1 fib n = (\(_, _, res, _) -> res) (until stop change (n, 1, 1, 1)) where stop (Integer, Integer, Integer, Integer) ->Bool stop (n, i, _, _) = n == i change (Integer, Integer, Integer, Integer) -> (Integer, Integer, Integer, Integer) change (n, i, old, vold) = (n, i+1, vold+old, old) fib Integer -> Integer fib 0 = 1 fib 1 = 1 fib n = fb n -- accumulering egen svansrekursiv where fb Integer->Integer->Integer->Integer-> Integer fb i vold old n n==i = old otherwise = fb (i+1) old (old+vold) n

11 Beräkning av alla Fibonacchitalen, Fibs fibslk [Integer] fibslk = 1 1 fixfibs fibslk fixfibs [Integer] -> [Integer] fixfibs (voldoldrest) = (vold+old) fixfibs (oldrest) fib Integer -> Integer fib n = fibslk!! (frominteger n) Fibs i kapitel 14 fibs [Integer] -- Hudak p 191 fibs = 1 1 zipwith (+) fibs (tail fibs) zipwith (a -> b -> c) -> [a] -> [b] -> [c] -- i Prelude(list) zipwith z (aas) (bbs) = z a b zipwith z as bs zipwith _ = [] Körning av fibs ((!!) [a] -> Int -> a i lista ta ut elemnt) går blixtsnabbt. Main> fibs!!

12 "Text-reduktion" av programmmet fibs i Kapitel 14, avsnitt Definition och den lata beräkning som Haskell tillämpar fibs [Integer] fibs = 1 1 add fibs (tail fibs) where add = zipwith (+) fibs => 1 1 add fibs (tail fibs) => fibs = 1 1 tf2 tf2 1 1 add (11tf2) (tail (11tf2) => 1 1 add (11tf2) (1tf2) => räknas ut lite grann bara en gång add (1tf2) (tf2) => Även om vi prövar utifrån måste för att göra tf2 = 2 tf3 add ha tf2 dvs måste göra lite på tf2 tf add (12tf3) (2tf3) => add (2tf3) (tf3) => räknas ut lite grann bara en gång Även om vi prövar utifrån måste vi för att göra lite add ha första elementen dvs måste göra lite tail, men början på fibs har vi

13 "Graf-reduktion" av programmmet fibs i Kapitel 14, avsnitt fibs [Integer] -- Hudak p 191 fibs = 1 1 zipwith (+) fibs (tail fibs) zipwith (a -> b -> c) -> [a] -> [b] -> [c] -- i Prelude(list) zipwith z (aas) (bbs) = z a b zipwith z as bs zipwith _ = [] fibs 1 1 tf = tail fibs zipwith (+) fibs 1 tf = tail fibs 1 tf2 2 zipwith (+) fibs 1 tf = tail fibs 1 tf2 2 3 tf3 zipwith (+)

14 Kap 14. server client- exemplet Kommentarer till Hudak p 194, 195. Definitioner och den lata beräkning som Haskell tillämpar reqs = client resps resps = server reqs server xs = map(+1) xs client ys = 1 ys reqs => client resps => 1 resps => 1 server reqs => 1 (map (+1) ) ( 1 tf2 ) reqs = 1 tr2 tr2 => 1 2 (map (+1) tr2 ) reqs = client resps resps = server reqs server xs = map(+1) xs client (yys) = if ok y then 1 y y else error ". reqs => client resps => client (server request) => client (server (client resps)) =>... värre och värre Katastrof! Ny definition av client ok y = True tr2 = 2 tr3 tr3 => (map (+1) tr3 ) Lösning 1 Inget avancerat mönster istället selektor client ys = 1 if ok (head ys) then ys else error ".." if inflyttat Lösning 2 (bättre) Lazy pattern client ~(yys) = 1 if ok y then y ys else error ".." if inflyttat Lazy pattern Lösning 3 client ~(yys@(yys)) = 1 if ok y then yys else error ".." Namn på helhet och delar if inflyttat

15 reqs = client resps = 1 resps resp = server reqs = map (+1) reqs 1 map (+1) reqs = client resps = 1 resps resp = server reqs = map (+1) reqs 1 2 map (+1)