;; The first three lines of this file were inserted by DrScheme. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-intermediate-reader.ss" "lang")((modname lect06-accum) (read-case-sensitive #t) (teachpacks ((lib "universe.ss" "teachpack" "2htdp"))) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ((lib "universe.ss" "teachpack" "2htdp"))))) ;;; Loops vs. Recursion ;;- contracts: ;(require scheme/contract) ;(define-struct/contract book ((name string?) (pages number?)) #:transparent) ;(define/contract (f x) ; (-> odd? even?) ; (+ x 1)) ; ;;See some more involved . ; ; ;; count-hellos-v1 : list-of-string -> natnum ;; Return the number of times "hello" occurs in `wrds` ;; (define (count-hellos-v1 wrds) (cond [(empty? wrds) 0] [(cons? wrds) (+ (if (string=? (first wrds) "hello") 1 0) (count-hellos-v1 (rest wrds)))])) ;; Compare to: Java version: ;; http://www.radford.edu/itec380/2009fall-ibarland/Lectures/lect06-accum/Looper.java ; ch2 : (list-of string) int -> int ; return the number of times "hello" occurs in `wrds` ; plus `hellos-so-far`. (define (ch2 wrds hellos-so-far) (cond [(empty? wrds) hellos-so-far] [(cons? wrds) (ch2 (rest wrds) (+ hellos-so-far (if (string=? (first wrds) "hello") 1 0)))])) (define (count-hellos wrds) (ch2 wrds 0)) ; ; Note the correspondence to the Java code -- ; statement-for-statement, this code does the same. ; ; The helper function ch2 is tail-recursive: ; The recursive call can be optimized away ; to a 'jmp' in the assembly code. ; Thus even though there might be 1000 recursive calls, ; no large stack of pending operations gets created. ; The *way* in which we converted 'count-hellos' into a ; tail-recursive version was to be clever and add an ; accumulator 'so-far' variable (which is exactly what w ; did in our Java loop as well). ; (Although they're related, don't confuse ; "tail recursion" ; [no work is needed after the recursive call finishes, ; therefore the recursive call's stack frame can be optimized away] ; with "accumulator variable", a variable that keeps track ; of data seen previously in the computation. ; If we had to give an English description of what ch2 returns, ; it'd be: ch2 returns ; the #times "hello" occurs in `wrds` + hellos-so-far ; ; Note how that description holds for each call (including ; all recursive ones). ; This statement is important in the Java code, too: ; it's the "loop invariant": ; every time you start the loop, ; (#times "hello" occurs in `wrds` + hellos-so-far) ; is the same value. ; This property is what convinces us that the code/loop ; is actually *correct*. (check-expect (count-hellos empty) 0) (check-expect (count-hellos (cons "frog" empty)) 0) (check-expect (count-hellos (cons "hello" empty)) 1) (check-expect (count-hellos (cons "frog" (cons "hello" empty))) 1) (check-expect (count-hellos (cons "fly" (cons "frog" empty))) 0) (check-expect (count-hellos (cons "hello" (cons "hello" empty))) 2) (check-expect (count-hellos (cons "ciao" (cons "aloha" (cons "hello" (cons "frog" (cons "hello" empty)))))) 2)