;; 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)