tail recursion and accumulators recursion
play

Tail Recursion and Accumulators Recursion Should now be - PowerPoint PPT Presentation

Tail Recursion and Accumulators Recursion Should now be comfortable with recursion: No harder than using a loop (Maybe?) OAen much easier than


  1. Tail ¡Recursion ¡and ¡Accumulators ¡

  2. Recursion ¡ Should ¡now ¡be ¡comfortable ¡with ¡recursion: ¡ • No ¡harder ¡than ¡using ¡a ¡loop ¡(Maybe?) ¡ ¡ • OAen ¡much ¡easier ¡than ¡a ¡loop ¡ ¡ – When ¡processing ¡a ¡tree ¡(e.g., ¡evaluate ¡an ¡arithmeFc ¡ expression) ¡ – Avoids ¡mutaFon ¡even ¡for ¡local ¡variables ¡ • Now: ¡ ¡ – How ¡to ¡reason ¡about ¡ efficiency ¡of ¡recursion ¡ – The ¡importance ¡of ¡ tail ¡recursion ¡ – Using ¡an ¡ accumulator ¡to ¡achieve ¡tail ¡recursion ¡ – [No ¡new ¡language ¡features ¡here] ¡

  3. Call-­‑stacks ¡ While ¡a ¡program ¡runs, ¡there ¡is ¡a ¡ call ¡ stack ¡of ¡funcFon ¡ calls ¡that ¡have ¡started ¡but ¡not ¡yet ¡returned ¡ – Calling ¡a ¡funcFon ¡ f ¡pushes ¡an ¡instance ¡of ¡ f on ¡the ¡stack ¡ – When ¡a ¡call ¡to ¡ f to ¡finishes, ¡it ¡is ¡popped ¡from ¡the ¡stack ¡ These ¡ stack ¡frames ¡store ¡informaFon ¡such ¡as ¡ • the ¡values ¡of ¡arguments ¡and ¡local ¡variables ¡ • informaFon ¡about ¡“what ¡is ¡leA ¡to ¡do” ¡in ¡the ¡funcFon ¡ (further ¡computaFons ¡to ¡do ¡with ¡results ¡from ¡other ¡ funcFon ¡calls) ¡ Due ¡to ¡recursion, ¡mulFple ¡stack-­‑frames ¡may ¡be ¡calls ¡to ¡ the ¡same ¡funcFon ¡

  4. Example ¡ (define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) (fact ct 0 0) (fact ct 1 1) (fact 1) => (* 1 _) (fact ct 2 2) (fact 2) => (* 2 _) (fact 2) => (* 2 _) (fact ct 3 3) (fact ct 3 3) = => ( (* 3 3 _) _) (fact 3) => (* 3 _) (fact 3) => (* 3 _) (fact ct 0 0) = => 1 1 (fact 1) => (* 1 _) (fact ct 1 1) = => ( (* 1 1 1 1) (fact 2) => (* 2 _) (fact 2) => (* 2 _) (fact ct 2 2) = => ( (* 2 2 1 1) (fact 3) => (* 3 _) (fact 3) => (* 3 _) (fact ct 3 3) = => ( (* 3 3 _) _) (fact ct 3 3) = => ( (* 3 3 2 2)

  5. What's ¡being ¡computed ¡ (fact 3) => (* 3 (fact 2)) => (* 3 (* 2 (fact 1))) => (* 3 (* 2 (* 1 (fact 0)))) => (* 3 (* 2 (* 1 1))) => (* 3 (* 2 1)) => (* 3 2) => 6

  6. Example ¡Revised ¡ (define (fact2 n) (define (fact2-helper n acc) (if (= n 0) acc (fact2-helper (- n 1) (* acc n)))) (fact2-helper n 1)) SFll ¡recursive, ¡more ¡complicated, ¡but ¡the ¡result ¡of ¡ recursive ¡calls ¡ is ¡the ¡result ¡for ¡the ¡caller ¡(no ¡ remaining ¡mulFplicaFon) ¡

  7. Example ¡Revised ¡ (define (fact2 n) (define (fact2-helper n acc) (if (= n 0) acc (fact2-helper (- n 1) (* acc n)))) (f2-h 1 1 6 6) (fact2-helper n 1)) (f2-h 2 2 3 3) (f2-h 2 3) => _ (f2-h 3 3 1 1) (f2-h 3 1) => _ (f2-h 3 1) => _ (fact ct2 3 3) (fact ct2 3 3) = => _ _ (fact2 3) => _ (fact2 3) => _ (f2-h 0 0 6 6) (f2-h 0 0 6 6) = => 6 6 (f2-h 1 1 6 6) = => _ _ (f2-h 1 1 6 6) = => _ _ (f2-h 1 1 6 6) = => 6 6 (f2-h 2 3) => _ (f2-h 2 3) => _ (f2-h 2 3) => _ (f2-h 2 3) => 6 (f2-h 3 1) => _ (f2-h 3 1) => _ (f2-h 3 1) => _ (f2-h 3 1) => _ (fact2 3) => _ (fact2 3) => _ (fact2 3) => _ (fact2 3) => _

  8. What's ¡being ¡computed ¡ (fact2 3) => (fact2-helper 3 1) => (fact2-helper 2 3) => (fact2-helper 1 6) => (fact2-helper 0 6) => 6

  9. An ¡opFmizaFon ¡ It ¡is ¡unnecessary ¡to ¡keep ¡around ¡a ¡stack-­‑frame ¡just ¡so ¡it ¡can ¡ get ¡a ¡callee’s ¡result ¡and ¡return ¡it ¡without ¡any ¡further ¡ evaluaFon ¡ ¡ Racket ¡recognizes ¡these ¡ tail ¡calls ¡in ¡the ¡compiler ¡and ¡treats ¡ them ¡differently: ¡ – Pop ¡the ¡caller ¡ before ¡the ¡call, ¡allowing ¡callee ¡to ¡ reuse ¡the ¡same ¡ stack ¡space ¡ – (Along ¡with ¡other ¡opFmizaFons,) ¡as ¡efficient ¡as ¡a ¡loop ¡ (Reasonable ¡to ¡assume ¡all ¡funcFonal-­‑language ¡ implementaFons ¡do ¡tail-­‑call ¡opFmizaFon) ¡ ¡includes ¡Racket, ¡Scheme, ¡LISP, ¡ML, ¡Haskell, ¡OCaml… ¡

  10. What ¡really ¡happens ¡ (define (fact2 n) (define (fact2-helper n acc) (if (= n 0) acc (fact2-helper (- n 1) (* acc n)))) (fact2-helper n 1)) (fact 3) (f2-h 3 1) (f2-h 2 3) (f2-h 1 6) (f2-h 0 6)

  11. Moral ¡ • Where ¡reasonably ¡elegant, ¡feasible, ¡and ¡important, ¡ rewriFng ¡funcFons ¡to ¡be ¡ tail-­‑recursive ¡can ¡be ¡much ¡more ¡ efficient ¡ – Tail-­‑recursive: ¡recursive ¡calls ¡are ¡tail-­‑calls ¡ ¡ • meaning ¡all ¡recursive ¡calls ¡must ¡be ¡the ¡last ¡thing ¡the ¡calling ¡funcFon ¡ does ¡ • no ¡addiFonal ¡computaFon ¡with ¡the ¡result ¡of ¡the ¡callee ¡ • There ¡is ¡also ¡a ¡methodology ¡to ¡guide ¡this ¡transformaFon: ¡ – Create ¡a ¡helper ¡funcFon ¡that ¡takes ¡an ¡ accumulator ¡ – Old ¡base ¡case's ¡return ¡value ¡becomes ¡iniFal ¡accumulator ¡value ¡ – Final ¡accumulator ¡value ¡becomes ¡new ¡base ¡case ¡return ¡value ¡

  12. (define (fact n) Old ¡base ¡case's ¡return ¡ (if (= n 0) 1 value ¡becomes ¡iniFal ¡ (* n (fact (- n 1))))) accumulator ¡value. ¡ (define (fact2 n) (define (fact2-helper n acc) (if (= n 0) acc (fact2-helper (- n 1) (* acc n)))) (fact2-helper n 1)) Final ¡accumulator ¡value ¡ becomes ¡new ¡base ¡case ¡ return ¡value. ¡

  13. Another ¡example ¡ (define (sum1 lst) (if (null? lst) 0 (+ (car lst) (sum1 (cdr lst))))) (define (sum2 lst) (define (sum2-helper lst acc) (if (null? lst) acc (sum2-helper (cdr lst) (+ (car lst) acc)))) (sum2-helper lst 0))

  14. And ¡another ¡ (define (rev1 lst) (if (null? lst) '() (append (rev1 (cdr lst)) (list (car lst))))) (define (rev2 lst) (define (rev2-helper lst acc) (if (null? lst) acc (rev2-helper (cdr lst) (cons (car lst) acc)))) (rev2-helper lst '()))

  15. Actually ¡much ¡be_er ¡ (define (rev1 lst) ; Bad version (non T-R) (if (null? lst) '() (append (rev1 (cdr lst)) (list (car lst))))) • For ¡ fact ¡and ¡ sum , ¡tail-­‑recursion ¡is ¡faster ¡but ¡both ¡ways ¡ linear ¡Fme ¡ • The ¡non-­‑tail ¡recursive ¡ rev ¡is ¡quadraFc ¡because ¡each ¡ recursive ¡call ¡uses ¡ append , ¡which ¡must ¡traverse ¡the ¡first ¡list ¡ – And ¡1 ¡+ ¡2 ¡+ ¡… ¡+ ¡(length-­‑1) ¡is ¡almost ¡length ¡* ¡length ¡/ ¡2 ¡ ¡ – Moral: ¡beware ¡ append , ¡especially ¡if ¡1 st ¡argument ¡is ¡result ¡of ¡a ¡ recursive ¡call ¡ • cons ¡is ¡constant-­‑Fme ¡(and ¡fast), ¡so ¡the ¡accumulator ¡version ¡ rocks ¡

  16. Tail-­‑recursion ¡== ¡while ¡loop ¡with ¡local ¡ variable ¡ (define (fact2 n) (define (fact2-helper n acc) (if (= n 0) acc (fact2-helper (- n 1) (* acc n)))) (fact2-helper n 1)) def fact2(n): acc = 1 while n != 0: acc = acc * n n = n – 1 return acc

  17. Tail-­‑recursion ¡== ¡while ¡loop ¡with ¡local ¡ variable ¡ (define (sum2 lst) (define (sum2-helper lst acc) (if (null? lst) acc (sum2-helper (cdr lst) (+ (car lst) acc)))) (sum2-helper lst 0)) def sum2(lst): acc = 0 while lst != []: acc = lst[0] + acc lst = lst[1:] return acc

  18. Tail-­‑recursion ¡== ¡while ¡loop ¡with ¡local ¡ variable ¡ (define (rev2 lst) (define (rev2-helper lst acc) (if (null? lst) acc (rev2-helper (cdr lst) (cons (car lst) acc)))) (rev2-helper lst '())) def rev2(lst): acc = [] while lst != []: acc = [lst[0]] + acc lst = lst[1:] return acc

  19. Always ¡tail-­‑recursive? ¡ There ¡are ¡certainly ¡cases ¡where ¡recursive ¡funcFons ¡ cannot ¡be ¡evaluated ¡in ¡a ¡constant ¡amount ¡of ¡space ¡ ¡ ¡ Example: ¡funcFons ¡that ¡process ¡trees ¡ 1 ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡2 ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡5 ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡3 ¡ ¡ ¡ ¡ ¡4 ¡ – Lists ¡can ¡be ¡used ¡to ¡ ¡ represent ¡trees: ¡ '((1 2) ((3 4) 5)) ¡ In ¡these ¡cases, ¡the ¡natural ¡recursive ¡approach ¡is ¡the ¡ way ¡to ¡go ¡ – You ¡could ¡get ¡one ¡recursive ¡call ¡to ¡be ¡a ¡tail ¡call, ¡but ¡ rarely ¡worth ¡the ¡complicaFon ¡ ¡

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend