Nada Tentamensdag 2004 okt 18 Tentamen Programmeringsparadigm Skrivtid 5 h Antalet uppgifter : 1 (allmänt)+ 4 (Haskell) + 4 (Prolog) = 10p +(6p + 18p +6p+ 20p) + (10p +12p + 8p +10p) = 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. OBS! Svara genom att lämna in sista sidan med kopia på denna svarsmatris! 10p) imperativ oo funktionell logisk För vilka paradigm gäller (kryssa i matrisen till vänster. Ibland flera kryss för varje påstående) a) Programmen har en logisk läsning och en procedurell läsning. b) Programmen består av bl a kommandon, bland annat tilldelningskommandon. c) Programmen saknar konventionella tilldelningskommandon. d) Programmen består av till stor del av definitioner av funktioner. e) Programmen består till stor del av definitioner av predikat. f) Programmen definierar aggregat av "variabler" och paket av kommandon ("metoder"). g) Paradigmen tillhör gruppen av deklarativa paradigm. h) Programmering kan ses som "programmering med matematik". i) Programmering kan ses som "programmering med logik". j) Programmering kan ses som "programmering med λ-kalkyl". k) Moderna språk i paradigmen avänder "högre ordningens funktioner". l) Vissa moderna språk i paradigmen använder "lat evaluering". m) I paradigmen får man en djupet-först-sökning "gratis". n) Denna paradigm uppfanns till stor del i Oslo. o) Den dominerande paradigmen fram till 1980. p) Den dominerande paradigmen nu. q) Vid körningen spelar föränding av innehållet i delar av minnet ("variabler") stor roll ("destruktiv uppdatering"). r) Vid körningen spelar dubbelsidig passning ("matchning", unifiering) mellan argument och vänsterled i definitioner stor roll. s) Ett sätt att förklara semantiken är att visa vad som händer i minnet i en von-neuman-dator, (= en förenklad modell av den vanliga datorn) t) Man kan beskriva pardigmen som att datorn vi körningen försöker att få ett uttryck sant. u) Man kan beskriva pardigmen som att datorn vi körningen försöker att beräkna ett matematiskt uttryck. v) I vissa moderna språk i paradigmen programmerar man helt utan sidoeffekter, till och med in och utmatning. z) Min favoritparadigm
Del : Funktionell programmering. I alla deluppgifterna, använd Haskell och skriv typen för de identifierare du definierar. 2. a) Skriv en funktionen null som avgör om det är sant eller osant om en lista är tom. Ange även funktionens typ. Denna funktion, som finns i Prelude används sällan, varför? Definiera även null med ett λ-uttryck, dvs null = < λ-uttryck>. Kan man alltid byta ut null mot λ-uttrycket? b) Skriv en funktionen signum med denna matematiska definition: 1 om 0 < signum() = 0 om =0-1 om < 0 6p) 3. a) I schacklabben kan man ha användning för en funktion (skrivs i modulen Square) netsquare :: Square {-from-} -> Square {-to-}-> Square {-net-} 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. b) I schacklabben kan man ha användning för en funktion (skrivs i modulen Square) betweensquares :: Square {-from-} -> Square {-to-} -> [Square] som givet en schackruta som man startar från och en schackruta som man är på väg till returnerar en lista med mellanliggande rutor när man går rakt eller diagonal. Skriv betweensquare.man behöver inte bekymra sig hur funktionen beter sig om man varken går rakt eller diagonalt (min lösning går diagonalt tills man kan gå rakt, sedan rakt). Tips: Jag använder netsquare och rekursion i min lösning; betweensquares för rutor från startrutan fram till slutrutan är ju nästa ruta från startrutan följt av rutorna med betweensquares från nästa ruta från startrutan till slutrutan. betweensquares används i alla följande deluppgifter. c) 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 eporterar 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) = onlyone [icm (isq, icm) <- ch, isq == sq] where onlyone :: [Chessman] -> Chessman onlyone (cm:[]) = cm onlyone _ = NoChessman Skriv freesquares utan att använda några högre ordningens funktioner eller listomfattning. När kan man använda newtype istället för data? Fördel? Tips: Jag använder en rekursiv hjälpfunktion check som kollar att det bara är tomma rutor i den lista med mellanliggande rutor som beräknas med betweensquares. d) Skriv funktionen freesquares med listomfattning. Tips: Jag kontrollerar om en lista med de rutor bland de mellanliggande rutorna som innehåller pjäser /= NoChessman är tom med hjälp av null. e) Skriv funktionen med map och filter. Tips: jag kontrollerar om en lista med pjäser /= NoChessman på de mellanliggande rutorna är tomma. Man kan nog även göra som i med i d) med map och filter istället för med listomfattning. f) Skriv funktionen med all (dvs kontrollera att alla mellanliggande rutor är tomma). Utdrag ur Prelude: and, or and or :: [Bool] -> Bool = foldr (&&) True = foldr ( ) False any, all :: (a -> Bool) -> [a] -> Bool any p = or. map p all p = and. map p g) Vilken av lösningarna c) - f) gillar du mest? 18p)
4 a) I Prelude finns en funktion break :: (a->bool) -> [a] -> ([a],[a]). T e break (\c -> c ==, ) "(1.0,14.0,1.0)" blir ( "(1.0", ",14.0,1.0)" ) Skriv en funktionen breakat :: a ->[a] -> ([a],[a]) med vars hjälp man t e kan göra breakat, "(1.0,14.0,1.0)" som ska bli ("(1.0",",14.0,1.0)") b) Antag att vi har denna funktion f :: String -> (String, String, String) f ( ( :cs) = let (s,, :yszsp) = breakat, cs (ys,, :zsp) = breakat, yszsp (zs, ) :rest) = breakat ) zsp in (s, ys, zs) Vad blir f "(1.0,14.0,1.0)"? 6p) 5 a) Skriv i Haskell en DT (datatyp) Vector3 i en module Vector3 (vektorer i rummet) med de operationer som definieras nedan i modulens början : module Vector3 ( -- 5 Vector3, -- datatyp för vektorer i rummet Vector3, -- Double-> Double-> Double->Vector3 Konstuktorfunktion read, -- String -> Vector3 inläsning på formen "Vector3 1.0 2.0 3.0" read1, -- String -> Vector3 inläsning på formen read1 "(1.0, 2.0, 3.0)" show, -- Vector3 -> String utskrift på formen "Vector3 1.0 2.0 3.0" show1, -- Vector3 ->String utskrift på formen "(1.0, 2.0, 3.0)" (==), -- Vector3 -> Vector3 -> Bool lika med (/=), -- Vector3 -> Vector3 -> Bool ej lika med add, -- Vector3 -> Vector3 -> Vector3 vektoradditon sub, -- Vector3 -> Vector3 -> Vector3 vektorsubtraktion, -- Vector3 -> Vector3 -> Vector3 kryssprodukt neg, -- Vector3 -> Vector3 negering lengthv3, -- Vector3 -> Double vektorlängd ( absolutbelopp) o, -- Vector3 -> Vector3 -> Double skalärprodukt ) where Eempel på körningar : Vector3 1.0 2.0 3.0 add Vector3 1.0 1.0 1.0 blir Vector3 2.0 3.0 4.0 lengthv3 (Vector3 1.0 2.0 3.0) blir 3.74166 Vector3 1.0 2.0 3.0 Vector3 1.0 1.0 1.0 blir Vector3 (-1.0) 2.0 (-1.0) show1 (read1"(1.0, 2.0, 3.0)" read1 "(1.0, 1.0, 1.0)") blir "(-1.0, 2.0, -1.0)" read1"(1.0, 2.0, 3.0)" add read1 "(1.0, 1.0, 1.0)" blir Vector3 2.0 3.0 4.0 show1 (read1"(1.0, 2.0, 3.0)" add read1 "(1.0, 1.0, 1.0)") blir "(2.0, 3.0, 4.0)" Vector3 1.0 2.0 3.0 + Vector3 1.0 1.0 1.0 blir Vector3 2.0 3.0 4.0 (tilläggsuppgift nedan) Tips: I show1 och read1 kan man ha glädje av show :: Show a => a->string och read :: Read a => String->a T e: read "1.0" + 1.0 blir 2.0. Många prelude-typer är instanser i Show och Read. Se även uppgift 4.a
b) Komplettera din definition i a) så att man kan använda följande operatorer och funktion i typklassen Num (detta är ganska svårt, talade om detta på föreläsning) -- Tillägsuppgift (+), -- överlagrad operator för add (-), -- överlagrad operator för sub (*), -- överlagrad operator för kryssprodukt negate -- överlagrad funktion för negate -- övriga funktioner i Num ger error Typklassen Num är definierad så här i "Prelude" : class (Eq a, Show a) => Num a where (+), (-), (*) :: a -> a -> a negate :: a -> a abs, signum :: a -> a frominteger :: Integer -> a fromint :: Int -> a -- Min comp def: All, -- ecept negate or (-) -- Def imp se prelude c) I uppgift b), varför kan vi inte använda lengthv3 för abs? Del : Logikprogrammering. 20p) 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. (10p) 7. Skriv i Prolog ett generate-and-test-program som löser följande problem: I en kappsegling deltar 7 båtar, bland annat Patricia. Spray kom precis innan Necesse. Endast Volo placerade sig precis mellan Maybee och Bonnie. Eakt en båt placerade sig mellan Spray och Maybee. Bigfoot kom precis mitt i resultatlistan. Hur ser resultatlistan ut? 12p)
8. Prologs semantik (procedurell läsning) kan beskrivas med Byrds bomodel. a) Kommer vi till en bo via Redo-porten kommer vi 1) alltid att lämna boen via Fail-porten. X) alltid att lämna boen via Call-porten. 2) att lämna boen via Fail-porten eller via Eit-porten b) Kommer vi till en bo via Call-porten kommer vi 1) alltid att lämna boen via Fail-porten. X) alltid att lämna boen via Eit-porten. 2) att lämna boen via Fail-porten eller via Eit-porten. c) Kommer vi till en bo via Redo- porten har vi 1) ofta lämnat efterföljande bo via Call-porten. X) ofta lämnat efterföljande bo via Eit-porten. 2) ofta lämnat efterföljande bo via Fail-porten. d) Har vi lämnat en Eit-port och sedan passerat ett snitt (cut,!) 1) kommer vi in i efterföljande bo (när sådan finns) via Call-porten. X) hoppar vi över efterföljande bo (när sådan finns). 2) startar en "backtracking" e) Har vi lämnat en Fail-port och sedan passerat ett snitt (cut,!) 1) kommer vi in i föregående bo (när sådan finns) via Redo-porten. X) kommer vi in i föregående bo (när sådan finns) via Call-porten. 2) kommer vi inte in i föregående bo (när sådan finns) via Redo-porten. 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?)?- a= b.?- A= b.?- a= B.?- A= B.?- m(adam, rut) = m(adam, rut).?- m(adam, rut) = m(adam, rut).?- m(adam, rut) = m(adam, Adam).?- m(adam, rut) = m(adam, Rut).?- m(adam, rut) = m(rut, Rut).?- m(adam, rut) = M(adam, rut). 8p) 10p)
Bifoga denna sida med de övriga svaren på din tentamen! imperativ oo funktionell logisk För vilka paradigm gäller (kryssa i matrisen till vänster. Ibland flera kryss för varje påstående) a) Programmen har en logisk läsning och en procedurell läsning. b) Programmen består av bl a kommandon, bland annat tilldelningskommandon. c) Programmen saknar konventionella tilldelningskommandon. d) Programmen består av till stor del av definitioner av funktioner. e) Programmen består till stor del av definitioner av predikat. f) Programmen definierar aggregat av "variabler" och paket av kommandon ("metoder"). g) Paradigmen tillhör gruppen av deklarativa paradigm. h) Programmering kan ses som "programmering med matematik". i) Programmering kan ses som "programmering med logik". j) Programmering kan ses som "programmering med λ-kalkyl". k) Moderna språk i paradigmen avänder "högre ordningens funktioner". l) Vissa moderna språk i paradigmen använder "lat evaluering". m) I paradigmen får man en djupet-först-sökning "gratis". n) Denna paradigm uppfanns till stor del i Oslo. o) Den dominerande paradigmen fram till 1980. p) Den dominerande paradigmen nu. q) Vid körningen spelar föränding av innehållet i delar av minnet ("variabler") stor roll ("destruktiv uppdatering"). r) Vid körningen spelar dubbelsidig passning ("matchning", unifiering) mellan argument och vänsterled i definitioner stor roll. s) Ett sätt att förklara semantiken är att visa vad som händer i minnet i en von-neuman-dator, (= en förenklad modell av den vanliga datorn) t) Man kan beskriva pardigmen som att datorn vi körningen försöker att få ett uttryck sant. u) Man kan beskriva pardigmen som att datorn vi körningen försöker att beräkna ett matematiskt uttryck. v) I vissa moderna språk i paradigmen programmerar man helt utan sidoeffekter, till och med in och utmatning. z) Min favoritparadigm Uppmaning: Svara gärna på kursenkäten, som du kan komma åt från kursidan! 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 (te e-pos, tel ):
Svar tentamen programeringsparadigm 2004- oktober. Del paradigmer allmänt. -- 1 imperativ oo funktionell logisk? För vilka paradigm gäller (kryssa i matrisen till vänster. Ibland flera kryss för varje påstående) a) Programmen har en logisk läsning och en procedurell läsning. b) Programmen består av bl a kommandon, bland annat tilldelningskommandon. c) Programmen saknar konventionella tilldelningskommandon. d) Programmen består av till stor del av definitioner av funktioner. e) Programmen består till stor del av definitioner av predikat. f) Programmen definierar aggregat av "variabler" och paket av kommandon ("metoder"). g) Paradigmen tillhör gruppen av deklarativa paradigm. h) Programmering kan ses som "programmering med matematik". i) Programmering kan ses som "programmering med logik". j) Programmering kan ses som "programmering med λ-kalkyl". k) Moderna språk i paradigmen avänder "högre ordningens funktioner". l) Vissa moderna språk i paradigmen använder "lat evaluering". m) I paradigmen får man en djupet-först-sökning "gratis". n) Denna paradigm uppfanns till stor del i Oslo. o) Den dominerande paradigmen fram till 1980. p) Den dominerande paradigmen nu. q) Vid körningen spelar föränding av innehållet i delar av minnet ("variabler") stor roll ("destruktiv uppdatering"). r) Vid körningen spelar dubbelsidig passning ("matchning", unifiering) mellan argument och vänsterled i definitioner stor roll. s) Ett sätt att förklara semantiken är att visa vad som händer i minnet i en von-neuman-dator, (= en förenklad modell av den vanliga datorn) t) Man kan beskriva pardigmen som att datorn vi körningen försöker att få ett uttryck sant. u) Man kan beskriva pardigmen som att datorn vi körningen försöker att beräkna ett matematiskt uttryck. v) I vissa moderna språk i paradigmen programmerar man helt utan sidoeffekter, till och med in och utmatning. z) Min favoritparadigm Del funktionell programmering. null :: [a] -> Bool -- 2 a null [] = True null _ = False -- Selektorer ("sönder-plocknings-funktioner") som null behövs sällan, man mönsterpassar ("pattern matchar") istället. null = \ list -> (list == []) Ja.
signum :: Integer -> Integer signum == 0 = 0 > 0 = 1 otherwise = -1 netsquare (Sq i1 j1) (Sq i2 j2) = Sq (i1 + signum (i2- i1)) (j1 + signum (j2-j1)) betweensquares sqfrom sqto sqfrom == sqto = [] sqm == sqto = [] otherwise = sqm : betweensquares sqm sqto where sqm = netsquare sqfrom sqto -- 2 b -- 3 a -- b freesquares sqfr sqto board = check (betweensquares sqfr sqto) --c where check [] = True check (sq:sqs) = chessmanat sq board == NoChessman && check sqs -- newtype ev istället för data (snabbare) när man har eakt en konstuerare. freesquares sqfr sqto board = null [ sq sq <- betweensquares sqfr sqto, chessmanat sq board /= NoChessman ] freesquares sqfr sqto b = null --e (filter ( /= NoChessman) -- enbart filter (\sq ->.. ) också OK (map (\sq -> chessmanat sq b) (betweensquares sqfr sqto))) --d freesquares sqfr sqto b = all (\sq -> chessmanat sq b == NoChessman) (betweensquares sqfr sqto) Lösning f. --f --g breakat c = break (==c) -- eller breakat c = break (\c1 -> c1 == c) -- 4 a -- eller breakat c s = break (\c1 -> c1 == c) s ( "1.0", "14.0", "1.0" ) -- 4 b module Vector3 ( {- eportlistan i tentanuppgiften -} ) where -- 5 a) data Vector3 = Vector3 Double Double Double deriving (Eq, Show, Read) -- ger (==) (/=) read show add :: Vector3 -> Vector3 ->Vector3 add (Vector3 1 y1 z1) (Vector3 2 y2 z2) = Vector3 (1+2) (y1+y2) (z1 + z2) sub:: Vector3 -> Vector3 ->Vector3 sub v1 v2 = add v1 (neg v2) neg :: Vector3 -> Vector3 neg (Vector3 y z) = Vector3 (-) (-y) (-z) lengthv3 :: Vector3 -> Double lengthv3 (Vector3 y z) = sqrt (* + y*y + z*z) breakat c = break (==c) -- 4a read1 :: String -> Vector3 -- modifikation av 4b) read1 ( ( :cs) = let (s,, :yszsp) = breakat, cs (ys,, :zsp) = breakat, yszsp (zs, ) :rest) = breakat ) zsp in Vector3 (read s) (read ys) (read zs) show1 :: Vector3 -> String show1 (Vector3 y z) = "(" ++ show ++ ", " ++ show y ++ ", " ++ show z ++")"
o :: Vector3 -> Vector3 -> Double o (Vector3 1 y1 z1) (Vector3 2 y2 z2) = (1*2 + y1*y2 + z1*z2) :: Vector3 -> Vector3 -> Vector3 (Vector3 1 y1 z1) (Vector3 2 y2 z2) = Vector3 (y1*z2 - z1*y2) (z1*2-1*y2) (1*y2 - y1*2) instance Num Vector3 where (+) = add (*) = negate = neg abs = error "abs" frominteger i = error "frominteger" -- 5 b -- Typerna stämmer ej. -- 5 c 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). % Ls is a result list of 7 boats in a race % 7 % 6 a race(ls) :- Ls = [_,_,_, bigfoot, _, _, _], member(patricia, Ls), follows(spray, necesse, Ls), between(maybee, volo, bonnie, Ls), onebetween(spray, maybee, Ls). % alt: between(spray,_, maybee, Ls) follows(x,y,[x,y _]). follows(x,y,[_ Zs]):- follows(x,y,zs). between(x,y,z,[x, Y, Z _]). between(x,y,z,[z, Y, X _]). between(x,y,z, [_ Us]) :- between(x,y,z, Us). member(x, [X _]). member(x, [_ Xs]) :- member(x,xs). onebetween(x,z, Ls) :- between(x,_,z,ls). /* Körning : Krävs ej i tenatmen?- race(rs). Rs = [bonnie,volo,maybee,bigfoot,spray,necesse,patricia] ; no */ % b % c 8a) 2 8b) 2 8c) 2 8d) 1 8e) 2 % 8?- a= b. no % 9?- A= b. A = b ; no?- a= B. B = a ; no?- A= B. A = B ; no?- m(adam, rut) = m(adam, rut). yes?- m(adam, rut) = m(adam, rut). Adam = adam? ; no?- m(adam, rut) = m(adam, Adam). no?- m(adam, rut) = m(adam, Rut). Rut = rut? ; no?- m(adam, rut) = m(rut, Rut). Rut = rut, Adam = rut? ;no?- m(adam, rut) = M(adam, rut). {SYNTAX ERROR:.. OBS: ; no "inga fler lösningar med andra substitutioner" bara no "unifierar ej"