CMPU101, Spring 2013 ;; Lecture #4 ; ANNOUNCEMENTS: Labs this week will meet on Thursday, Feb. 7th ; (section 51) and Friday, Feb. 8th (section 52). ; ; The BEGIN special form: (SPECIAL FORM 3) ; ; Last week, we learned how to define mathematical functions ; and how to call defined functions on numeric arguments. ; ; In each case, we had a single mathematical expression inside ; the lambda special form and the evaluation of that expres- ; sion was the return value when the function was called. But ; what if we want to include more than one expression inside ; the body of a function? ; ; Why would you want to do this? One popular way to debug a ; program is by inserting printf statements inside functions. ; ; What is the return type of a printf statement? ; ; ---------------------------- ; ; The begin special form allows a programmer to write more than ; one expression inside the body of a function while still ; obeying the restrictions that HtDP languages impose on the ; number of expressions inside the body. Multiple expressions ; are evaluated from the top down and ONLY THE VALUE OF THE ; LAST EXPRESSION IS RETURNED. Since printf statements only ; have side-effects, you can write an arbitrary number of ; printf statements after a begin and these side-effects will ; be run before the function returns its final value. ; ; ; For example, consider the function we wrote in lecture 3, to ; return the distance between 2 points in the plane. If we ; wanted to print information about the inputs prior to ; returning the final value, we could define the function ; as shown below in function distance-v2 (to be done in class): ; (define distance-v2 (lambda (x1 y1 x2 y2) (begin ;; The following 4 lines print the values of all the ;; parameters, the intermediate computations and the ;; final result. (printf "x1=~a, x2=~a, y1=~a, y2=~a~%" x1 x2 y1 y2) (printf "(expt (- x1 x2) 2) => ~A~%" (expt (- x1 x2) 2)) (printf "(expt (- y1 y2) 2) => ~A~%" (expt (- y1 y2) 2)) (printf "Final value is ~%") (sqrt (+ (expt (- x1 x2) 2) (expt (- y1 y2) 2)))))) ; NOTE: THE LINE BELOW MUST BE UNCOMMENTED IN ORDER TO RUN THE ; DISTANCE-V2 FUNCTION. ;(distance-v2 4 3 0 0) ;; Call this function and see what is printed ;after printf statements are added in class. ;; The function shown below uses the begin special form and ;; is also legal, but the purpose of the begin is impossible to ;; justify: (define useless-function (lambda (input) (begin ; the printf generates a side-effect, printing to the ; interactions window. The return value of the prinf is void, but the ; text does print when the function is run (printf "input is ~a~%" input) (* input input) (* input input input) input ;; the following statement is the only thing ever returned by this ;; function. empty))) ;; What do you think the final output of this function is for the ;; input 3? EMPTY 77? EMPTY ; NOTE: AT LEAST ONE OF THE FUNCTION CALLS BELOW MUST BE UNCOMMENTED ; IN ORDER FOR THE USELESS FUNCTION TO BE EVALUATED. ;(useless-function 3) ;(useless-function 77) ;; There will be more to say about the begin special form in the ;; upcoming weeks, but for now be aware that it exists and that ;; our purpose for using it will usually involve side-effect ;; printing. ; ; AUTOMATIC FUNCTION TESTING: ; ; It would be tedious to have to compare the result of every ; evaluated expression with the expected output if the defini- ; tions window contained many expressions. ; ; The check-expect special form is used to verify the result of ; expression evaluation for an entire program. It does all the ; tests AFTER running the program and reports how many tests ; passed at the end. ; ; ; CHECK-EXPECT: (SPECIAL FORM 4) ; ; * automates the process of testing. ; ; * used when the value of an output is exact. ; ; You should write test cases with check-expect BEFORE ; you write any function definition. At run-time, ; check-expects are executed after the definition. ; ; The form of calls to check-expect is: ; ; (check-expect test-expression expected-result) ; ; We will use the check-expect function to evaluate most ; of the functions we write, before writing the function. ; ; You can use check-expect statements to verify almost any ; expression (with the exception of functions that produce ; images, scenes, or random numbers). ; ; When you have multiple check-expect statements in one ; program, they will have a cumulative output...a report ; on how many tests passed. If any of the tests do not ; pass, the result will be a pop-up box that tells you ; which test(s) did not pass and what the real result of ; that test(s) is. ; ; Use check-expect statements on the expressions given ; below (in class): ; ; UNCOMMENT THE EXPRESSIONS BELOW TO SEE HOW CHECK-EXPECT WORKS. ;(check-expect (+ 1 (+ 2 (+ 3 (+ 4 5)))) 15) ; ;(check-expect (* (+ 2 2) (/ (* (+ 3 5) (/ 30 10)) 2)) 48) ; ;(check-expect (remainder 12 5) 2) ; ;(check-expect (abs -5) 5) ; ;(check-expect (string-length "Hello, world") 12) ; ;(check-expect (string=? "larry" "larry" "larry" "larry") true) ; ;(check-expect (string=? "larry" "larry" "larry" "shirley") #f) ; ;(check-expect (string->number "19") 19) ; ;(check-expect (string->number "hello") false) ; ;;; circle is a 3-parameter function that produces the image of ;;; a circle. The call below creates a circle with radius=20 in ;;; solid red. ; ;(check-expect (image-width (circle 20 "solid" "red")) 40) ; ; CHECK-WITHIN: (SPECIAL FORM 5) ; ; * used when the value of an output may be inexact, ; e.g., if the output is a repeating decimal number. ; ; You should write test cases with check-within before the ; function definition and at run-time they are executed ; after the definition. ; ; The form of calls to check-within is: ; ; (check-within test-expression expected-result tolerance) ; ; where the tolerance is the error allowed between the ; expected answer and the actual answer. ; ; UNCOMMENT THE EXPRESSIONS BELOW TO SEE HOW CHECK-WITHIN WORKS. ;; Use check-within to test the following expressions: ;(check-within (exact->inexact 5) 5.0 1.0) ;(check-within (/ 1.0 3.0) 0.333 0.001) ;(check-within (exp 3) 20.0 0.1) ;; e raised to the third power ; ; DESIGN RECIPE FOR FUNCTIONS: ; ; 1. Write a contract, header, and purpose statement in comments. ; The header should include the actual parameter names. ; ; 2. Write as many check-expects as necessary to convince yourself ; you know how the function should work for a representative ; sample of elements in the input domain BEFORE you write the ; function. ; ; 3. Write the function. Include comments in the code if ; any part is not explained fully. ; ; 4. Write post-function printf's to generate some meaningful ; output. ; ; 5. Run the function, making sure that all tests pass. ; ;; Ex1: Define the function CONVERT-3 to assemble a 3-digit number ;; from the three digits it consumes. The first parameter is ;; interpreted as the most significant digit (in the hundreds ;; position), the second as the digit in the tens position, and ;; the third as the least significant digit in the ones position. ;; The function outputs the number represented by the addition ;; of the digits multiplied by their base-10 position. ; Contract: (convert-3 digit digit digit) -> number (integer) ; Header: (define convert-3 (lambda (hund tens ones) ...)) ; Purpose: Convert series of digits into one number ; Constants: (define H 100) (define T 10) ; Pre-function tests: (check-expect (convert-3 8 7 5) 875) (check-expect (convert-3 0 7 5) 75) (check-expect (convert-3 0 0 0) 0) ; Function definition: (define convert-3 (lambda (hund tens ones) (+ (* hund H) (* tens T) ones))) ; Post-function printf's: (printf "(convert-3 8 7 5) => ~a~%" (convert-3 8 7 5)) (printf "(convert-3 0 0 0) => ~a~%" (convert-3 0 0 0)) (printf "(convert-3 9 0 1) => ~a~%" (convert-3 9 0 1)) ;; Ex2: Write a function called REVERSE-ORDER that consumes two ;; strings and outputs them in reverse order, separated by ;; one space, as a single string. NOTE: Only the strings ;; are returned in the opposite order as they appear in the ;; parameter list, you do not have to reverse all the ;; characters in the strings. ;Contract: (reverse-order string string) -> string ;Header: (define reverse-order (lambda (str1 str2) ... )) ;Purpose: Return "str2 str1"--str2 appended to space appended ; to str1. ;Pre-function tests: (check-expect (reverse-order "kitty" "hello") "hello kitty") (check-expect (reverse-order "" "hello") "hello ") (check-expect (reverse-order "kitty" "") " kitty") ;Function definition: (define reverse-order (lambda (str1 str2) (string-append str2 " " str1))) ;Post-function printf's: (printf "(reverse-order \"birthday\" \"happy\") => \"happy birthday\" => ~a~%" (reverse-order "birthday" "happy")) (printf "(reverse-order \"kitty\" \"hello\") => \"hello kitty\" => ~a~%" (reverse-order "kitty" "hello")) (printf "(reverse-order \"star\" \"death\") => \"death star\" => ~a~%" (reverse-order "star" "death")) ; ; PREDICATE FUNCTION: Any function that returns a boolean. ; ; Relational operators for numbers: =, <, <=, >, >= ; Each of these functions take any number of numeric inputs ; and produce a boolean, either true (#t) or false (#f) ; ; Logical operators for booleans: AND, OR, NOT: ; ; (and true true false) ==> #f (SPECIAL FORM 6) ; Boolean arguments evaluated left to right until either ; a false value found (in which case the output is false ; and no more of the expressions are evaluated) or all ; boolean expressions are true (in which case the output ; is true). ; ; (or false false true) ==> #t (SPECIAL FORM 7) ; Boolean arguments evaluated left to right until either ; a true value found (in which case the output is true ; and no more of the expressions are evaluated) or all ; boolean expressions are false (in which case the output ; is false). ; ; (not #t) ==> #f ; Produces the opposite boolean value as its argument. ; ; --------------------------- ; ; Predict the value of the following expressions: ; ; (and (> 5 4) (>= 3 3)) ==> #t ; (and (or (> 5 4) (>= 2 3)) #t) ==> #t ; (or (and (> 5 4) (>= 7 3)) #f) ==> #t ; (not (<= 7 9)) ==> #f ; ; NOT, AND & OR are presented on pages 43-45 of ; our lecture notes. ; ;; Ex3: Write a function called bigger-than? that consumes ;; 3 numbers and returns true only if the first number ;; is larger than the second and the third is larger ;; than either the first or second. ;Contract: (bigger-than? number number number) -> boolean ;Header: (define bigger-than? (lambda (n1 n2 n3) ...)) ;Purpose: Return true if n1 > n2 and either n3 > n1 or n3 > n2. ;Pre-function tests: (check-expect (bigger-than? 5 5 5) false) (check-expect (bigger-than? 5 2 3.5) #t) (check-expect (bigger-than? 253.25 253 255) true) ;Function definition: (define bigger-than? (lambda (n1 n2 n3) (and (> n1 n2) (or (> n3 n2) (> n3 n1))))) ;Post-function printf's: (printf "(bigger-than? 4 3 3.5) => ~a~%" (bigger-than? 4 3 3.5)) (printf "(bigger-than? 5 5 5.5) => ~a~%" (bigger-than? 5 5 5.5)) (printf "(bigger-than? 100 0 -4) => ~a~%" (bigger-than? 100 0 -4))