AID-nummer: Datum: 2011-06-10 1 Tekniska högskolan vid Linköpings universitet Institutionen för datavetenskap Anders Haraldsson TDDC74 Programmering, abstraktion och modellering Tentamen Fredag 10 juni 2011 14-18 Uppgifterna löses direkt på denna uppgiftslapp, som lämnas in i sedvanligt tentamensomslag. Räcker inte utrymmet kan du komplettera med lösa papper. Skriv tydligt så att inte dina lösningar missförstås. Använd väl valda namn på parametrar etc. Även om det i uppgiften står att du skall skriva en funktion, så får du gärna skriva ytterligare hjälpfunktioner, som kan vara nödvändiga. Enligt den nya standarden i Scheme/Racket använder man en ny uppsättning funktioner för cons-celler man vill ändra pekare i (dvs muterbara cons-celler), dvs mcons, mcar, mcdr, set-mcar!, set-mcdr! etc. Det går lika bra att använda cons, car, cdr, set-car!, set-cdr!. Betygsgradering: 12-16,5 betyg 3 17-20,5 betyg 4 21-24 betyg 5 Lycka till
AID-nummer: Datum: 2011-06-10 2 Uppgift 1. Beräkning av uttryck och quote (2 poäng) Vi ger följande uttryck för beräkning. Vilket värde skrivs ut eller om det blir fel, beskriv typen av fel. > (define (a x y) (+ x y z)) > (define b (lambda (z) (list a 1 z))) > (define z (+ 1 2 3)) > z = > 'z = > (quote z) = > '(a 1 5) = > (a z z) = > (cons '(z z) '(w)) = > (define c (b 1)) > c = > ((lambda (x y) (+ x x y y)) (car (cdr c)) 5) = > ((car c) 1 2) = 0-2 rätt 0p 3-4 rätt 0,5p 5-6 rätt 1,0p 7-8 rätt 1,5p 9 rätt 2,0p
AID-nummer: Datum: 2011-06-10 3 Uppgift 2. Rekursiva funktioner (9 poäng) 2a. (3p) Skriv en rekursiv funktion (vänd lst), som vänder elementen på toppnivån i en lista. > (vänd '(a b c d)) => (d c b a) (define (vänd lst) Beskriver din funktion en rekursiv eller iterativ (linear) processkösning. Visa med substitutionsmodellen med exemplet (vänd '(a b c)). 2b. (3p) Skriv en funktion (vänd-alla lst), som vänder elementen i alla listorna oavsett nivån. > (vänd-alla '(a (b (c d) e) f)) => (f (e (d c) b) a) (define (vänd-alla lst)
AID-nummer: Datum: 2011-06-10 4 Uppgift 2. Rekursiva funktioner, forts 2c. (2p) Skriv en rekursiv funktion (generera start nästa-element-fn antal), som tar ett startvärde och beräknar nästföljande värde genom att beräkna nästa-element-fn på det tidigare värdet. Man skall beräkna antal värden, som returneras i en lista. Se exemplen som följer: > (generera 10 (lambda (e) (+ e 2)) 5) => (10 12 14 16 18) ; dvs 5 tal genereras, start med 10 och där efterföljande tal ; ökas med 2. > (generera 'a list 3) => (a (a) ((a))) ; 3 element genereras (define (generera start nästa-fn antal) 2d. (1p) Använd funktionen generera för att skapa en lista, som är en tabell med n och n! (n fakultet). Starta med 1!=1. För att skapa en tabell med alla fakulteter från 1! Till 7! kan vi skriva enligt följande: (generera start?? fn?? 7) = ((1 1) (2 2) (3 6) (4 24) (5 120) (6 720) (7 5040)) Ge de två saknade argumenten start?? fn?? start?? = fn?? =
AID-nummer: Datum: 2011-06-10 5 Uppgift 3. Par/cons-celler (2 poäng) 3a. (1 p) Vad blir värdet i parentesformat av följande uttryck. Rita även upp värdet med den grafiska representationen med cons-celler och pekare (box and pointer notation). > (define en-lista (list (list 'x) (cons 'a '(b)))) en-lista => 3b. (1p) Skriv ett Scheme-uttryck som skapar följande struktur top a b c () Vad händer i strukturen ovan då vi gör > (let ((d-cell (mcons 'd '()))) (set-mcdr! (mcdr top) d-cell) (set-mcdr! top d-cell)) Inför ändringarna i ovanstående struktur.
AID-nummer: Datum: 2011-06-10 6 Uppgift 4. ADT Abstrakta datatyper Objektorientering (4 poäng) En ring är en datastruktur, som är cirkulär, och som har en toppekare som anger ett element i ringen, ett ringelement. Man kan flytta toppekaren framåt eller bakåt för att ange föregående eller nästa ringelement och förflyttningarna är cyklist, dvs. man kan gå runt flera varv i strukturen och det finns ingen början eller slut. Man kan lägga till ett nytt element före det ringelement, som toppekaren för tillfället anger, som då anges med toppekaren. Exempel: Vi skapar en abstrakt datatyp ring med följande primitiva operationer: skapa-ring : -> ring lägg-till : element x ring -> ring ta-bort : ring -> ring framåt : ring -> ring bakåt : ring -> ring tom-ring? : ring -> sanningsvärde toppen : ring -> element skriv-ut : ring -> ; lägg in ett element före elementet toppekaren anger ; toppekaren anger det nya elementet ; tar bort det element som toppekaren anger ; toppekaren anger nästföljande ringelement ; flyttar toppekaren ett steg framåt ; flyttar toppekaren ett steg bakåt ; saknar ringen ringelement? ; ringelementet, som toppekaren anger ; med början av det ringelement som toppekaren anger Vi kan nu skapa en ring *min* och använda operationerna: > (define *min* (skapa-ring)) > (set! *min* (lägg-till 'kalle *min*)) > (set! *min* (lägg-till 'lisa *min*)))) > (skriv-ut *min*) = [lisa kalle ] > (set! *min* (lägg-till 'stina *min*)))) > (skriv-ut *min*) = [stina lisa kalle ] > (toppen *min*) = stina > (set! *min* (framåt *min*)) > (toppen *min*) = lisa > (skriv-ut *min*) = [lisa kalle stina ] > (set! *min* (bakåt *min*)) > (skriv-ut *min *) = [stina lisa kalle ] > (set! *min* (bakåt *min*)) > (set! *min* (bakåt *min*)) > (toppen *min*) = lisa > (skriv-ut *min*) = [lisa kalle stina ] > (set! *min* (ta-bort *min*)) > (skriv-ut *min*) = [kalle stina ] > (set! *min* (ta-bort *min*)) > (set! *min* (ta-bort *min*)) > (skriv-ut *min*) = [ ] > (tom-ring? *min*) = #t
AID-nummer: Datum: 2011-06-10 7 Vi kan representera ringelementen som en vanlig lista, som börjar med toppekaren, en conscell med symbolen *ring*, som anger övriga ringelement. Att gå framåt och bakåt i ringen innebär att listan måste struktureras om. Vi definierar de primitiva operationerna: (define (skapa-ring) (cons '*ring* '())) (define (lägg-till e ring) (cons '*ring* (cons e (cdr ring)))) (define (ta-bort ring)???) (define (toppen ring) (car (cdr ring))) (define (framåt ring)???) (define (bakåt ring) (if (tom-ring? ring) ring (cons '*ring* (flytta-sista-först (cdr ring))))) (define (flytta-sista-först lista) (define (iter l res) (if (null? (cdr l)) (cons (car l) res) (iter (cdr l) (append res (list (car l)))))) (iter lista '())) (define (tom-ring? ring) (null? (cdr ring))) (define (skriv-ut ring) (display "[") (map (lambda (e) (display e) (display " ")) (cdr ring)) (display "...]") (newline)) Uppgift: 4a. (2p) Definiera funktionerna ta-bort och framåt.
AID-nummer: Datum: 2011-06-10 8 Uppgift 4. ADT Abstrakta datatyper Objektorientering, forts 4b. (2p) Gör en objektorienterad paketering av den abstrakta datatypen ring. Du skall skissa strukturen på kod, och den behöver ej vara fullständig, men man skall kunna förstå vilka förändringar du kommer att göra. Visa hur motsvarande kod ser ut för att skapa *min* och några av operationerna från exemplet.
AID-nummer: Datum: 2011-06-10 9 Uppgift t 5. Högre ordningens procedurer (3 poäng) På föreläsningarna och i SICP-boken visades hur man kunde implementera derivering av en funktion (med ett argument) genom nedanstående gränsvärdesövergång, då dx går mot 0. Nu kan vi inte göra själva gränsövergången, men kan definiera att litet värde på dx. Vi önskar implementera en procedur (deriv g), som returnerar en ny funktion, som kan beräkna derivatan av g för ett värde x. Observera att vi får ett approximativt värde. Vi kan då definiera f(x) = x 3 + 5x 2 + 3x + 5 och ge ett litet värde till dx. > (define f (lambda (x) (+ (* x x x) (* 5 x x) (* 3 x) 5))) > (define dx 0.001) > (deriv f) Definiera deriv. (define (deriv g) Givet proceduren deriv. Hur skriver du i Scheme för att beräkna f (2) 1, dvs vi förväntar oss få värdet ungefär 35. Definiera en procedur (n-deriv g n) som skapar n:te derivatan av en funktion g. > (define andra-derivatan-av-f 2 (n-deriv f 2)) > (andra-derivatan-av-f 3) = ungefär 28 (define (n-deriv g n) 1 Förstaderivatan av f blir f (x) = 3x 2 + 10x + 3 2 Andraderivatan av f blir f (x) = 6x + 10
AID-nummer: Datum: 2011-06-10 10 Uppgift 6. Procedurobjekt, omgivningsdiagram (4 poäng) 6a. (2p) I samband med omgivningsdiagram förklara bindning (binding) ram (frame) omgivning (environment) procedurobjekt (procedure object) Förklara hur omgivningsdiagrammet används då man i Scheme ger följande uttryck: definition: (define variabel uttryck) i en omgivning En tilldelning: (set! variabel uttryck) i en omgivning En lambda-uttryck: (lambda formella-parametrar kropp) i en omgivning En funktionsapplicering: (procedur-uttryck aktuella-parametrar ) i en omgivning En Förklara begreppen med hjälp av följande exempel genom att rita upp omgivningsdiagrammet och ange i den ordning som uttrycken beräknas vad som händer i omgivningsdiagrammet: > (define f (lambda (a b) (set! a (+ a 1)) (+ a b))) > (f 1 5) =?
AID-nummer: Datum: 2011-06-10 11 Uppgift 6. Procedurobjekt, omgivningsdiagram, forts 6b. (2p) Rita upp omgivningsdiagrammet när följande uttryck ges till Scheme. Du skall ange i vilken ordning ramar, bindningar och procedurobjekt skapas. Efter beräkningarna skall du ange vilka ramar som ej längre behövs och kan tas bort av en garbage collector. Vad gör funktionen? > (define (gen-circ lista) (let ((circ lista)) (lambda () (if (null? circ) (set! circ lista)) (let ((res (car circ))) (set! circ (cdr circ)) res)))) > (define c (gen-cric '(1 2 3))) > (c) = 1 > (c) = 2 > (c) = 3 > (c) = 1 > (c) = 2 etc.