Nada Tentamensdag 2005 jan11 Tentamen Programmeringsparadigm Skrivtid 5 h Antalet uppgifter : 1 (allmänt)+ 4 (Haskell) + 4 (Prolog) = 10p +(6p + 10p +14p+ 20p) + (9p +11p + 8p +12p) = 10p + 50p + 40 p = 100p Lärare, jourhavande lärare : Leif Kusoffsky ------------------------------------------------------------------------------------------------------------------ Tillåtna hjälpmedel : Brna : Prolog Programming Fokker : Functional programming eller Chakravaty, Keller: Introduction to Computing ----------------------------------------------------------------------------------------------------------------- Del : Paradigmer allmänt. 1. Beskriv olika programeringsparadigm och vad som utmärker dem. Ge exempel på olika programmeringsspråk i de olika paradigmen. 10 p) Del : Funktionell programmering. I alla deluppgifterna, använd Haskell och skriv typen för de identifierare du definierar. 2. a) Skriv en funktionen onlyone som avgör om det är sant eller osant om en lista innehåller exakt ett element. Ange även funktionens typ. b) Skriv en funktionen signum med denna matematiska definition: 1 om 0 < x signum(x) = 0 om x =0-1 om x < 0 6p) 3. a) I schacklabben kan man ha användning för en funktion (skrivs i modulen Square) nextsquare :: Square {-from-} -> Square {-to-}-> Square {-next-} som givet en schackruta som man startar från och en schackruta som man är på väg till returnerar den första rutan på väg till slutrutan när man går rakt eller diagonal. Skriv funktionen, givet denna deklaration : data Square = Sq Int Int deriving (Show, Eq) Man behöver inte bekymra sig hur funktionen beter sig om man inte går rakt eller diagonalt. Tips: Jag använder signum från 2b) i min lösning. 3p) b) I schacklabben kan man ha användning för en funktion (skrivs i modulen Chess) freesquares :: Square -> Square -> Chess -> Bool som kollar om alla mellanliggande rutor mellan två rutor är tomma. Deklarationer i Chess: import Chessman import Square -- Square ADT exporterar typen Square i 3a newtype Chess = Chess [(Square, Chessman)] deriving Show vänd!
Givet dessa deklarationer i Chessman: module Chessman import Square data Colour = data Kind where -- spelar ingen roll i denna uppgift = -- spelar ingen roll i denna uppgift data Chessman = Cman Colour Kind NoChessman -- schackpjäsen "tom ruta". deriving (Show, Eq) chessmanat :: Square -> Chess -> Chessman chessmanat sq (Chess ch) = theone [icm (isq, icm) <- ch, isq == sq] where theone :: [Chessman] -> Chessman theone (cm:[]) = cm theone _ = NoChessman Skriv freesquares. I oktobertentan löses uppgiften på en mängd olika sätt genom att arbeta med en lista med mellanliggande rutor, som framställdes med betweensquares. Nu tänker jag i första hand på att skriva en direkt, rekusiv lösning, se tips, men det är tillåtet att göra på andra sätt. När kan man använda newtype istället för data? Fördel? Tips: Jag använder nextsquare och rekursion i min lösning; freesquares för rutor från startrutan fram till slutrutan är ju sant om nästa ruta från startrutan är ledig och (rekursivt) att det är sant att rutorna från nästa ruta från startrutan till slutrutan är tomma. Basfallet är t ex att freesquares är sant om startrutan == slutrutan. (7p) 4. Skriv i i Haskell en funktion swaplist som skiftar komponeterna i alla par i en lista. De par där båda komponeterna är lika skall ej finnas med i resultatlistan. Exempel : Main> swaplist [(5,4),(15,14),(2,2),(14,14),(35,34)] [(4,5),(14,15),(34,35)] a) Skriv en lösning som vare sig använder högre ordningens funktioner, ackumulering i parameter, eller listomfattning. b) Skriv en lösning som använder ackumulering i parameter. c) Skriv i i Haskell en funktion swap som skiftar komponeterna i ett par. d) Skriv i i Haskell en funktion pneq som kontrollerar att komponeterna i ett par är olika. e) Skriv en lösning för swaplist som använder map, filter, swap och pneq. f) Skriv en lösning för swaplist som använder listomfattning. g) Skriv en lösning för swaplist som använder map, filter och lamda-uttryck (anonyma funktioner) i stället för swap och pneq. (14p)
5 a) Skriv en funktion (Pytagoras sats) distbetween:: ((Float, Float), (Float, Float)) -> Float som givet ett par med två kordinater ((x1, y1), (x2, y2)) i ett rätvinkligt koordinatsystem returnerarar avståndet mellan koordinaterna. Exempel..> distbetween ((0.0, 0.0), (3.0, 4.0)) blir 5.0 6p) b) Definiera triarea :: (Float, Float) -> (Float, Float) -> (Float, Float) -> Float som givet koordinaterna för tre hörn i ett rätvinkligt kordinatsystem returnerarar arean för triangeln bestämd av de tre hörnen. Tips: Använd Herons formel : A = sqrt (s*(s-a)*(s-b)*(s-c)) där a, b, c är längden på triangels sidor och s = 0.5*(a+b+c) 6p) c) Skriv i Haskell en modul för en datatype Shape för några olika geometriska former. Man skall kunna definera värden som är rektanglar givet två sidor cirklar givet radien rätvinkliga trianglar givet de två katetrarna polygoner givet en lista med kordinater för hörnen Dessutom skall det finnas (exporteras) en vanliga funktion square (ej konstuerar-funktion) som returnerar en kvadrat (givet sidan). Till slut skall det i ADT Shape finnas (exporteras) en funktion area :: Shape -> Float som retunerar arean för en geometrisk form (se även fråga b). v1 Tips: Polygoners yta kan beräknas genom att dela upp en polgon i en mindre polygon och en triangel (för triangelns yta kan du använda funkitonen i 2 b): v2 v5 v3 v4 v2 v3 = + v1 v1 v5 v3 v4 d) På IKEA kan man tänka sig att man kan inhandla en rund cylindrisk kastrull med radien 3.0 och höjden 4.0. Skriv ett uttryck vars värde utgör kastrullens volym. 20p)
Del : Logikprogrammering. 6. a) Skriv ett predikat för select(x,harxs,ettmindrexs) med betydelsen att listan EttMindreXs är resultatet av att en förekomst av X har tagits bort från HarXs. b) Skriv ett predikat för member(element,list) med betydelsen Element är ett element i listan List med hjälp av select. c) Skriv ett predikat för choosetwofrom(list, E1, E2) med betydelsen att E1 och E2 är två olika element i listan List med hjälp av select och member. (9p) 7) Skriv i Prolog ett generate-and-test-program som löser följande problem (modifierat efter Sterling and Shapiro): Three friends came first, second, and third in a programming competition. Each of the three has a different first name, likes a different sport and has a different nationality. Michael likes basketball and did better than the American. Sven, the Swede, did better than the tennis player. The cricket player came first. Who is the Australian? What sport does Richard play? (11p) 8. a) Om Prolog misslyckas med att unifiera argumenten i ett delmål f(..) med huvudet (konklusionen) i den första av flera klausuler som definierar predikatet f så 1) svarar Prolog yes. X) svarar Prolog no. 2) försöker Prolog unifiera argumenten med huvudet i den andra klausulen för predikatet f. b) Om ett Haskell-system, t ex hugs, misslyckas med att passa ("matcha") argumenten i ett anrop f.. med vänsterledet i den första av flera ekvationer som definierar funktionen f så 1) svarar hugs med Program error. X) returneras False. 2) försöker hugs "matcha" argumenten med vänsterledet i den andra ekvationen för funktionen f. c) Om Prolog misslyckas med att satisfiera ett delmål g i en konjunktion av delmål.., h(..), g(..), f(x) så 1) försöker Prolog på nytt att få delmål h att lyckas. X) svarar Prolog no. 2) svarar Prolog yes. vänd!
d) Om ett Haskell-system, t ex hugs, vid en körning får resultatet False vid beräkningen av funktionanropet g(x)i detta uttryck med funktionanrop h(x) && g(x) && f(x) så 1) anropas h(x) på nytt. X) blir hela uttrycket True om uttrycket f(x), som beräknas, blir True. 2) blir hela uttrycket False 9 När man kör i Prolog-fönstret i emacs, vad skulle följande körningar (unifieringar) ge för resultat (Lyckas unifieringarna? Vilka substitutioner görs i så fall?) 8p)?- X(a) = X(a).?- X(a) = x(a).?- x(a) = Y(a).?- x(a) = y(a).?- x(a) = x(a).?- x(a) = x(b).?- x(a) = x(b).?- x(a) = x(b).?- x(a) = X(A).?- x(a) = x(a).?- stockh(del(norrmalm, X), Y) = stockh(del(z, nk), sv).?- stockh(del(norrmalm, X), X)= stockh(del(z,nk), Y). 12p) Förfrågan: Kan du tänka dig att vara labbassistent nästa år under läsperiod 1 och 2 i kursen programmeringsparadigm 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 ):
Svar tentamen programeringsparadigm 2005- januari. Del paradigmer allmänt. Imperativ : Sekvens av kommandon (satser/order/instuktioner) som datorn utför i tidsordning. Ordningen kan brytas med aternativkommandon (if / case /switch osv ) och med slingkommandon ( Loopar / for / while / repeat- until osv) och i vissa språk med goto. Assemleringspråk, Fortran, Basic, Pascal... osv. Det finns hur många som helst. Moderna imperativa språk möjliggör definiton av egna sammansatta typer; poster (records) och arrayer. OO : Imperativ + klassbegrepp, dvs posterna kan innehålla funktioner/procedurer = "metoder". Instanser av olika klasser kallas objekt, och anrop av metoderna sker via objekten. Detta innebär att objekt som är av av olika "sort" (tillhör olika klasser) "gör saker på sitt sätt". Dessutom kan klasserna inordnas i ett arvsträd (eller arvsordning). Språk: Eifel, Simula, Java, C++ m.fl. Funktionella språk. Programmering genom att definiera funktioner, "huvudprogram", "fuktioner", "subrutiner", metoder" ersätts av funktioner. Kärnan är matematikens lamda-kalkyl. Funktioner är värden, funktioner kan ha funktioner som argument och/eller resultat ("Högre ordningens funktioner"). Inga sidoeffekter, dvs en viss kod betyder alltid samma sak oberoende av exekveringsomgivning och oberoende av när den exekveras. Funktionsargument "mönsterpassas" ofta på parametrarna i funktionsdefiionerna, vilket är bekvämt. Språk: Haskell, ~ Lisp, ml. Lamda-uttryck finns också i Python och Python kan därför användas funktionellt. Logik språk. Kärnan är en delmängd av logiken. Programmering i Prolog genom att skriva logiska påståenden (klausuler, satser), dels fakta (endast ett vänsterled), dels regler av typ detta gäller ("klausulhuvud",konklusion, vänsterledet) om detta gäller ("klausulkropp", premiss, högerledetledet). Klausulkroppar består ofta av flera termer med "logiska och" som operator."logiska eller" skrivs i regel som flera klausuler och som tillsammans bildar ett predikat.predikat är alla klusuler med samma namn i konklusionen och samma ställighet. Både klausulhuvud och klausulkropp kan innehålla logiska variabler, och ett logikspråk försöker genom ("dubbelsidig") mönsterpassning (unifiering) klura ut om påståenden är sanna eller om logiska variabler förekommer vad som krävs av de logika variablerna för att påstenden ska vara sanna.språk: Prolog och moderna utvidgningar av Prolog. Del funktionell programmering. onlyone :: [a] -> Bool -- 2 a onlyone (x:[]) = True onlyone _ = False signum :: Integer -> Integer signum x x == 0 = 0 x > 0 = 1 otherwise = -1 nextsquare (Sq i1 j1) (Sq i2 j2) = Sq (i1 + signum (i2- i1)) (j1 + signum (j2-j1)) -- 2 b -- 3 a freesquares vstart vstop b = -- 3 b let vnext = nextsquare vstart vstop cha = chessmanat vnext b in (vnext == vstop) (cha == NoChessman && freesquares vnext vstop b) swaplist :: Eq a => [(a, a)] -> [(a, a)] -- 4
swaplist [] = [] -- a swaplist ((a, b) : abps) a == b = swaplist abps otherwise = (b, a):swaplist abps swaplist list = sl list [] -- b where sl :: Eq a => [(a, a)] -> [(a, a)] -> [(a, a)] sl [] acc = acc sl ((a, b) : abps) acc a == b = sl abps acc otherwise = sl abps (acc ++ [(b, a)]) swap :: (a, b) -> (b, a) -- c swap (a, b) = (b, a) pneq :: Eq a => (a, a) -> Bool -- d pneq (a,b) = a /= b swaplist :: Eq a => [(a, a)] -> [(a, a)] -- e swaplist list = map swap (filter pneq) list) swaplist list = [ (b, a) (a,b) <-list, pneq (a,b)] -- f swaplist list = map (\(a, b) -> (b, a)) (filter (\(a, b) -> a /= b) list) -- g distbetween :: ((Float, Float),(Float, Float)) -> Float -- 5a) distbetween ((x1, y1), (x2, y2)) = sqrt ((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) triarea :: (Float, Float) -> (Float, Float) -> (Float, Float) -> Float -- 5b) triarea v1 v2 v3 = sqrt (s*(s-a)*(s-b)*(s-c)) where a = distbetween (v1, v2) b = distbetween (v2, v3) c = distbetween (v3, v1) s = 0.5*(a+b+c) module Shape (Shape(..), area, square) where -- 5 c) data Shape = Rectangle Float Float Circle Float RtTriangle Float Float Polygon [(Float, Float)] square :: Float -> Shape square s = Rectangle s s area :: Shape -> Float area (Rectangle s1 s2 ) = s1*s2 area (Circle r ) = r * r * pi area (RtTriangle s1 s2 ) = 0.5*s1*s2 area (Polygon (v1:v2:v3:[])) = triarea v1 v2 v3 area (Polygon (v1:v2:v3:vs)) = triarea v1 v2 v3 + area (Polygon (v1:v3:vs)) Shape> 4.0*area (Circle 3.0) -- 5 d) 113.097
Del logik programmering. select(x, [X Xs], Xs). select(x, [Y Ys], [Y Zs]) :- select(x, Ys, Zs). member(x, Xs):- select(x, Xs, _). ChooseTwoFrom(List, E1, E2) :- select(e1,list, Es), member(e2, Es). % a person is p(name, sport, nationality) % 7 puzzle(ps) :- Ps = [p(_, cricket, _), p(_, _, _), p(_, _, _)], member(p(richard, _, _), Ps), member(p(_, _, aussie), Ps), did_better(p(michael, basket, _), p(_, _, american), Ps), did_better(p(sven, _, swede), p(_, tennis, _), Ps). did_better(x,y,[x Ys]) :- member(y, Ys). did_better(x,y,[_ Zs]):- did_better(x,y,zs). member(x, [X _]). member(x, [_ Ys]) :- member(x, Ys). % 6 a % b % c 2 2 1 2 % 8?- X(a) = X(a). {SYNTAX ERROR... % 9?- X(a) = x(a). {SYNTAX ERROR...?- x(a) = Y(a). {SYNTAX ERROR...?- x(a) = y(a). no?- x(a) = x(a). yes?- x(a) = x(b). no?- x(a) = x(b). A = b? ; no?- x(a) = x(b). B = A? ; no?- x(a) = X(A). {SYNTAX ERROR...?- x(a) = x(a). true? ; no?- stockh(del(norrmalm, X), Y) = stockh(del(z, nk), sv). X = nk, Y = sverige, Norrmalm = Z? ; no?- stockh(del(norrmalm, X), X)= stockh(del(z,nk), Y). X = nk, Y = nk, Norrmalm = Z? ; no OBS: ; no "inga fler lösningar med andra substitutioner" bara no "unifierar ej"