;; CS101, Spring 2013 ;; Lecture #6 ;; (require 2htdp/image) ; REQUIRE Special form No. 9 ; ; Used to include libraries without using the "add teach- ; pack" menu item. ; ; The image library contains the built-in functions for ; images like circle, square, text, etc. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; RECURSIVE FUNCTIONS are presented in Part 4 of the pdf ;; lecture notes, pages 53-61. ; ; DEFINITION OF RECURSIVE FUNCTION: ; A recursive function calls itself. ; --------------- ; ; At first you might think such a function would be defined ; something like this: ; ; (define rec-func ; (lambda (x) ; (rec-func x))) ;; NOT A TERMINATING RECURSIVE FUNCTION; ; ;; GOES INTO AN INFINITE LOOP ; ; ; ; The general pattern of recursive functions: ; ; 1. The body of a recursive function contains a decision ; statement (if, cond) involving one of the parameters ; of the function. We say that the recursion is done OVER ; the type of data contained in that parameter (e.g., ; natural numbers) and we call it the recursive parameter. ; ; 2. There is at least one base case, or stopping condition, ; to end the function execution. In the base case, the ; function does not call itself, it just tests the ; recursive parameter and returns a value. ; ; 3. There is at least one recursive case, or repeating ; condition, in which the function calls itself with a ; different argument that is closer to the base case ; than the current recursive parameter value. ; ; Instead of an infinite loop, the execution of a recursive ; function can be better described as a spiral that eventually ; ends in a base case. ; ;;------------------------------------------------------------- ;; Ex1: A classic recursive function is the factorial function, ;; which is defined as follows: ;; ;; n! = 1 if n = 1 or 0 (base cases) ;; = n * (n - 1)! otherwise (n > 1) ;; The factorial function: ; CONTRACT: (facty non-neg-integer) -> pos-integer ; HEADER: (define facty (lambda (n) ...)) ; PURPOSE: compute the factorial of num ; PRE-FUNCTION TESTS: (check-expect (facty 0) 1) (check-expect (facty 1) 1) (check-expect (facty 2) 2) (check-expect (facty 3) 6) (check-expect (facty 4) 24) (check-expect (facty 5) 120) ; FUNCTION: (define facty (lambda (n) (cond ;; base case, n = 0 or 1 [(<= n 1) 1] ;; recursive case, n! = n * (n-1)! [else (* n (facty (sub1 n)))]))) ; POST-FUNCTION PRINTFs: (printf "(facty 0) => ~a~%" (facty 0)) (printf "(facty 3) => ~a~%" (facty 3)) (printf "(facty 6) => ~a~%" (facty 6)) ;; Each recursive call to facty sets up a new local ;; environment with a unique value for n (the diagram ;; below is from page 57 of our pdf lecture notes). ;; NOTE: The figure below will not appear in a .txt file (text only). ;(scale 2.) ;; Look up the function scale to determine what the expres- ;; sion above does. ;;----------------------------------------------------- ;; Ex2: Write a function that sums all the numbers ;; between 0 and a positive natural number x. ; CONTRACT: (sum non-neg-integer) --> non-neg-integer ; HEADER: (define sum (lambda (x) ...)) ; PURPOSE: Sum the natural numbers from 0 to x. ; PRE-FUNCTION TESTS: (check-expect (sum 5) 15) (check-expect (sum 0) 0) (check-expect (sum 1) 1) (check-expect (sum 10) 55) ;;FUNCTION: (define sum (lambda (x) (cond ; base case, return 0 [(= x 0) 0] ; recursive case, add n to recursive call on n-1 [else (+ x (sum (sub1 x)))]))) ; ;; POST-FUNCTION PRINTFs: (printf "(sum 5) => ~a~%" (sum 5)) (printf "(sum 6) => ~a~%" (sum 6)) (printf "(sum 10) => ~a~%" (sum 10)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Write a function to print a line of dashes of a specified length. ; CONTRACT: (print-n-dashes pos-integer) --> void, side-effect printing ; HEADER: (define print-n-dashes (lambda (n) ...)) ; PURPOSE: Print "-" repeated n times, followed by a newline. ; Constant used in function: (define DASH "-") ; PRE_FUNCTION TESTS: Can't check-expect side-effect printing ; (use the IW to do post-function printfs). ; FUNCTION: (define print-n-dashes (lambda (n) (cond ; base case: return newline to end the line of dashes [(= n 0) (newline)] ; recursive case: print a single dash and do rec. call on n-1 [else (begin (printf DASH) (print-n-dashes (sub1 n)))]))) ;; POST-FUNCTION TESTS (PRINTF'S NOT USED BECAUSE OF VOID RETURN TYPE (print-n-dashes 1) (print-n-dashes 5) (print-n-dashes 10) ; ; Summary of features typical for recursive functions: ; ; • The body of the function contains a decision statement that ; tests a stopping condition, commonly called a base case. If ; that stopping condition evaluates to #t, then no more recursive ; function calls are made. ; ; • The body of the function contains an expression that involves a ; recursive call to that same function, but with different input(s). ; It is crucial that the inputs to the recursive function call be ; different in some way than the current recursive parameter--other- ; wise, that recursive function call would lead to another identical ; recursive function call, and so on, infinitely. ; ; • Because the inputs to the recursive function call use arguments ; that are closer to the base case, the recursive function call ; is not circular -- instead, the sequence of recursive function calls ; is more like a spiral that eventually stops when the base case occurs. ; ; • Although the expression in the body of the function is identical in ; each recursive function call, it is evaluated with respect to a ; different local environment. In other words, the evaluation of the ; body is affected by the value of the input parameter(s). This helps ; to avoid circularity and infinite loops. ; ;;; Example: Write a function that consumes a positive natural number and ;; returns the nth harmonic number as follows: ;; ;; H_n = 1 + 1/2 + 1/3 + 1/4 ... + 1/n ;; ; Contract: (harmonic positive-integer) -> number ; Header: (define harmonic (lambda (n) ...)) ; Purpose: To compute the nth harmonic number. ; Pre-function tests: (check-expect (harmonic 1) 1) (check-expect (harmonic 2) 1.5) (check-within (harmonic 3) 1.833 1) ; Function definition: (define harmonic (lambda (n) (cond ;; base case is 1/1, return 1 [(= n 1) 1] ;; recursive case: add 1/n to recursive call [else (+ (/ 1 n) (harmonic (sub1 n)))]))) ; Post-function printf's: (printf "(harmonic 1) => ~a~%" (harmonic 1)) (printf "(harmonic 10) => ~a~%" (exact->inexact (harmonic 10))) (printf "(harmonic 2001) => ~a~%" (exact->inexact (harmonic 2001))) (printf "(log 2001) => ~A~%" (log 2001))