Procedurer och villkor (define lessorequal (lambda (x y) (or (< x y) (= x y)))) (define between (lambda (x y z) (and (lessorequal x y) (lessorequal y z)))) > (between 3 4 5) #t > (between 3 2 5) #f DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 1 / 1
Rekursiva procedurer Vad är en rekursiv procedur? Hur beräknas en rekursiv procedur? Hur definieras en rekursiv procedur? Mera rekursiva procedurer Svansrekursion Bra om du åtminstone skummat igenom i AS: Example: Square Roots by Newton s Method samt Procedures as Black-Box Abstractions Procedures and the Processes They Generate Linear Recursion and Iteration Tree Recursion DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 2 / 1
Exempel: n-fakultet Vi vill definiera n-fakultet i Scheme. I matematiken kan n-fakultet definieras på följande sätt: n! = 1 2... (n 1) n Då n är känd, säg lika med 4, kan vi beräkna 4! genom att multiplicera fyra heltal: >(define fyra-fakultet (* 1 2 3 4)) >fyra-fakultet 24 DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 3 / 1
Exempel: n-fakultet... Då n är lika med 6, kan 6! beräknas på motsvarande sätt: >(define sex-fakultet (* 1 2 3 4 5 6)) >sex-fakultet 720 Hur definierar vi en procedur för n-fakultet då n inte är konstant? Vi kan inte förkorta ett Scheme-uttryck med... : >(define n-fakultet (* 1 2... (- n 1) n)) DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 4 / 1
Exempel: n-fakultet... Vi använder istället en annan matematisk definition av n!: n! = { 1 om n = 0 (basfall) n (n 1)! om n > 0 som definierar n! med hjälp av (n 1)! För att beräkna n! multiplicerar vi n med det vi får vid beräkning av (n 1)!, för att beräkna (n 1)! multiplicerar vi n 1 med det vi får vid beräkning av (n 2)!,... tills vi kommer till 0!, som enligt basfallet är lika med 1. DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 5 / 1
Exempel: n-fakultet... En Scheme-procedur som utför ovanstående beräkningssteg definieras nära nog exakt som den ovanstående matematiska definitionen: >(define factorial (lambda (n) (if (= n 0) 1 (* n (factorial (- n 1)))))) Factorial är en rekursiv procedur eftersom procedurkroppen till factorial innehåller ett anrop av factorial själv. Anropet inuti procedurkroppen kallas ett rekursivt anrop. Att använda factorial: >(factorial 4) 24 DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 6 / 1
Hur beräknas en rekursiv procedur? Generellt sett, så använder man rekursiva procedurer för att utföra en sekvens av upprepade beräkningar, men hur sker beräkningen? Genom att använda substitutionsmodellen, får vi följande beräkningssteg: Först expansionsfasen: 1. (factorial 4) 2. (if (= 4 0) 1 (* 4 (factorial (- 4 1)))) 3. (* 4 (factorial 3)) 4. (* 4 (if (= 3 0) 1 (* 3 (factorial (- 3 1))))) DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 7 / 1
Hur beräknas en rekursiv procedur?... (* 3 (factorial (- 3 1))))) 5. (* 4 (* 3 (factorial 2))) 6. (* 4 (* 3 (if (= 2 0) 1 (* 2 (factorial (- 2 1)))))) 7. (* 4 (* 3 (* 2 (factorial 1)))) 8. (* 4 (* 3 (* 2 (if (= 1 0) 1 (* 1 (factorial (- 1 1))))))) 9. (* 4 (* 3 (* 2 (* 1 (factorial 0))))) 10. (* 4 (* 3 (* 2 (* 1 (if (= 0 0) 1 (* 1 (factorial (- 1 1)))))))) fullt expanderad: 11. (* 4 (* 3 (* 2 (* 1 1)))) DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 8 / 1
Hur beräknas en rekursiv procedur?... 11. (* 4 (* 3 (* 2 (* 1 1)))) så en avvecklingsfas: 12. (* 4 (* 3 (* 2 1))) 13. (* 4 (* 3 2)) 14. (* 4 6) 15. 24 DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 9 / 1
Hur beräknas en rekursiv procedur?... Under expansionsfasen blir uttrycket normalt större och större (eller längre och längre) via substitutionerna. Under avvecklingsfasen blir uttrycket normalt mindre och mindre (eller kortare och kortare). För vissa rekursiva procedurer kan expansionsfasen och avvecklingsfasen falla samman. För att se expansionsfasen och avvecklingsfasen för rekursiva procedurer på skärmen, använd trace: DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 10 / 1
Hur beräknas en rekursiv procedur?... >(trace factorial) >(factorial 4) expansions-fas: [factorial 4] [factorial 3] [factorial 2] [factorial 1] [factorial 0] avvecklings-fas: 1 1 2 6 24 DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 11 / 1
Mer exempel på rekursion Gör en procedur som givet två argument, bas och tal, ger det minsta naturliga talet n så att bas n > tal. Detta kan beräknas så: 1. Testa först om bas 0 > tal. Om villkoret är uppfyllt, så är 0 det n vi söker eftersom 0 är det minsta naturliga talet. 2. Annars, testa om bas 1 > tal. I så fall är n = 1 det sökta talet. 3. Annars, testa om bas 2 > tal. I så fall är det n = 2 vi söker. 4.... DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 12 / 1
Mer exempel på rekursion... Denna beräkningssekvens fortsätter tills vi hittat ett n så att bas n > tal. Det funna värdet på n returneras som resultat. I Scheme kan vi definiera en rekursiv procedur som utför ovanstående beräkning. (define power-close-to (lambda (bas tal n) (if (> (expt bas n) tal) n (power-close-to bas tal (+ n 1))))) DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 13 / 1
Felsökning Använd trace för att se vilka argumentvärden som används och vilka värden som returneras i mellanstegen. >(trace power-close-to) >(power-close-to 4 80 0) [power-close-to 4 80 0] [power-close-to 4 80 1] [power-close-to 4 80 2] [power-close-to 4 80 3] [power-close-to 4 80 4] 4 >(untrace power-close-to) >(power-close-to 4 80 0) 4 DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 14 / 1
Svansrekursion För att utföra exponentberäkningar av typen b n, där n är ett positivt heltal, kan följande rekursiva definition användas: b n = b b (n 1) b 0 = 1 DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 15 / 1
Svansrekursion... Detta kan översättas till schemeproceduren: (define expt-1 (lambda (b n) (if (= n 0) 1 (* b (expt-1 b (- n 1)))))) Gör vi trace på expt-1 så får vi följande utskrift: DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 16 / 1
Svansrekursion... > (trace expt-1) (expt-1) > (expt-1 2 4) [expt-1 2 4] [expt-1 2 3] [expt-1 2 2] [expt-1 2 1] [expt-1 2 0] 1 2 4 8 16 16 DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 17 / 1
Svansrekursion... Multiplikationerna görs efter de rekursiva anropen. Innan multiplikationerna börjar beräknas, växer uttrycket på grund av de rekursiva anropen. Detta gör att mer minnesuttrymme krävs ju fler rekursiva anrop som utförs. DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 18 / 1
Svansrekursion... En alternativ definition av exponentberäkningen: (define expt-2 (lambda (b n) (expt-2-svans b n 1))) (define expt-2-svans (lambda (b n res) (if (= n 0) res (expt-2-svans (- n 1) (* b res))))) (trace expt-2-svans) DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 19 / 1
Svansrekursion... Nu får vi följande utskrift: > (expt-2 2 4) [expt-2-svans 2 4 1] [expt-2-svans 2 3 2] [expt-2-svans 2 2 4] [expt-2-svans 2 1 8] [expt-2-svans 2 0 16] 16 16 Multiplikationerna görs samtidigt som rekursiva anropen, vilket gör uttrycken i mellanstegen inte växer. Inget extra minnesutrymme krävs för de rekursiva anropen. Sådana rekursiva procedurer kallas för svansrekursiva procedurer. DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 20 / 1
Svansrekursion... Factorial definierades rekursivt, men kan naturligtvis få en svansrekursiv definition: (define fac-2 (lambda (n) (fac-2-svans n 2 1))) (define fac-2-svans (lambda (n m res) (if (> m n) res (fac-2-svans n (+ m 1) (* res m))))) (trace fac-2-svans) DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 21 / 1
Svansrekursion... >(fac-2 5) [fac-2-svans 5 2 1] [fac-2-svans 5 3 2] [fac-2-svans 5 4 6] [fac-2-svans 5 5 24] [fac-2-svans 5 6 120] 120 120 Den svansrekursiva proceduren ger upphov till en iterativ process. DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 22 / 1
Svansrekursion... Rekursiv procedur rekursiv process (define add-1 (lambda (a b) (if (= a 0) b (+ 1 (add-1 (- a 1) b))))) [add-1 3 4] [add-1 2 4] [add-1 1 4] [add-1 0 4] 4 5 6 7 Tänk: Proceduren är inte svansrekursiv eftersom den utför en beräkning på resultatet av det rekursiva anropet DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 23 / 1
Svansrekursion... Rekursiv procedur iterativ process (define add-2 (lambda (a b) (if (= a 0) b (add-2 (- a 1) (+ b 1))))) [add-2 3 4] [add-2 2 5] [add-2 1 6] [add-2 0 7] 7 Tänk: Proceduren är svansrekursiv eftersom den inte utför någon beräkning på resultatet av det rekursiva anropet DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 24 / 1
Nästa gång: Kan man definiera variabler och procedurer så att de är dolda? Kan man gömma dem? Vi ska titta lite på Blockstrukturer Omgivningar Enkel problemlösning Läs gärna i AS: Example: Square Roots by Newton s Method samt Procedures as Black-Box Abstractions DA2001 (Föreläsning 4) Datalogi 1 Hösten 2012 25 / 1