;; CMPU101, Spring 2013 ;; Lecture #3 ;;; Consider the following expressions. What happens when you type ;;; each one in the interactions window? NONE OF THESE NAMES ARE ;;; DEFINED, SO TYPING THEM IN THE INTERACTIONS WINDOW WILL PRODUCE ;;; AN ERROR ;;; ;;; NUM ;;; LAB ;;; THING ;;; THING2 ;;; XXX ;;; YYY ;;; Next, consider the following expressions. They do not generate ;;; any "return" value; but they do have side-effects. Uncomment ;;; the following lines and then click on the "Run" button. (define NUM 1000) (define LAB 'now) (define THING 'NUM) (define THING2 NUM) (define XXX (+ 2 3)) (define YYY '(+ 2 3)) ;;; Nothing happened, right? But now re-type the earlier expressions ;;; (NUM, LAB, etc.) into the Interactions window. You don't get any ;;; errors this time because the define statements wrote the names ;;; and associated values into the global environment. ;;; Question: What happens to the value of THING2 when NUM is changed? ;;; ANSWER: NOTHING HAPPENS BECAUSE NO VALUE IN THE GLOBAL ENVIRONMENT ;;; CAN BE RE-DEFINED, SO THERE IS NO WAY (THAT WE KNOW OF) ;;; TO CHANGE THE VALUE STORED FOR NUM. HOWEVER, EVEN IF WE ;;; DID CHANGE NUM, THE VALUE OF THING2 WOULD STILL BE 1000. ; ; The DEFINE special form: (SPECIAL FORM 1) ; ; The keyword define is called a special form because it is not ; evaluated according to the default rule. The word define is read, ; but is not looked up in the global environment (there is no entry ; for keywords in that table). ; ; The purpose of the define special form is to create a new entry ; in the global environment (GE). Specifically, for the expression ; ; (define X (+ 5 (* 4 2 3))) ; ; the symbol X is written into the name column of the GE and the ; value 29 is written as the value for X in the GE. The only part of ; the expression that is evaluated is the last subexpression, and ; the result of that evaluation is written in the GE as the value ; of X. ; ; Evaluation of a define statement returns nothing...its side- ; effect is the creation of a new name/value pair in the GE. ; ; ----------------------------------------- ; ; But how do we define our own function names? We need another ; specialform called LAMBDA. (SPECIAL FORM 2) ; ;;; LAMBDA expressions are SPECIAL FORMS that evaluate to PROCEDURES! ;;; Their form is inspired by Alonzo Church's Lambda Calculus. ;;; ;;; The form is: ;;; ;;; (lambda ( ... ) ;;; ;;; ) ;;; ;;; The result of EVALUATING such a LAMBDA expression is a procedure ;;; that expects N inputs (represented by the list of N parameters ;;; ... ). Each of these parameters has a unique name. ;;; ;;; Here's how to call this nameless procedure on N input arguments ;;; ... : (Notice that there must be N arguments since the ;;; lambda expression specifies N parameters.) ;;; ;;; ((lambda ( ... ) ;;; ) ;;; ... ) ;;; ;;; This function invocation obeys the Default Rule because the first ;;; entry after the leftmost parenthesis is a function, albeit a nameless ;;; one. ;;; ;;; When evaluating the expression in the of the lambda, any ;;; occurrence of a symbol that appears in the parameter list will ;;; evaluate to the corresponding argument. The arguments ... ;;; are matched, in order, with the parameters ... ;;; ;;; ;;; Thus, the evaluation of symbols in the parameter list does NOT ;;; use the Global Environment! ;;; ;;; In effect, the names ... are names that exist ;;; only inside the ()s of the lambda expression. ;;; ;;; The lambda expression returns the value that results from evaluating ;;; its body. ; ; What is the return value of the calls to unnamed lambda expressions given ; in (a) through (c) (the last one is a bit tricky): ; ; (a) ((lambda (x) (+ x 2)) 5) ==> 7 ; ; (b) ((λ (x y) (+ x (* y 3))) 7 4) ==> 19 ; ; (c) ((λ (x) ((λ (y) (* y 2)) (+ x 3))) 4) ==> 14 ; ; ; The following are examples of well-formed (i.e., valid) lambda ; expressions: ; ; 1) (λ () 44) ==> ZERO-PARAMETER FUNCTION ; ; 2) (λ (x) (* x x)) ==> ONE-PARAMETER FUNCTION ; ; 3) (λ (w h) (* w h)) ==> TWO-PARAMETER FUNCTION ; ; 4) (λ (r h) (* 1/3 3.14159 r r h)) ==> TWO-PARAMETER FUNCTION ; ; 5) (λ (x y z)(+ x(− y z))) ==> THREE-PARAMETER FUNCTION ; ; In contrast, the following are examples of malformed lambda ; expressions: ; ; 1) (λ (x y x) (* x y)) ;; x should not be repeated in parameter list ; ; 2) (λ (x 10) (* x 10)) ;; a parameter cannot be a literal value ; ; 3) (λ x) ;; no parentheses after the lambda for a ; ;; parameter list ; ; Why are these last 3 lambda expressions invalid? SEE ABOVE ; ; Example 1: Write a lambda expression that returns the value of its ; single numeric argument cubed. ; ANSWER: (λ (x) (expt x 3)) ;; THERE ARE OTHER WAYS TO WRITE THIS ; ; Call this expression on the input values 5, 4 and -1 (this ; will require 3 different calls). ((λ (x) (expt x 3)) 5) ((λ (x) (expt x 3)) 4) ((λ (x) (expt x 3)) -1) (newline) ; To show these calls in the interactions window, use 3 printf's: (printf "((λ (x) (expt x 3)) 5) => ~a~%" ((λ (x) (expt x 3)) 5)) (printf "((λ (x) (expt x 3)) 4) => ~a~%" ((λ (x) (expt x 3)) 4)) (printf "((λ (x) (expt x 3)) -1) => ~a~%" ((λ (x) (expt x 3)) -1)) (newline) ; ; Example 2: Write a lambda expression that takes 2 numeric arguments and ; returns the result of adding the square of the first argument ; to the cube of the second. ; ANSWER: (λ (x y) (+ (* x x) (expt y 3))) (newline) ; ; Call this expression on input values x=1 y=4 ; x=3 y=8 ; x=-2 y=-2 (printf "((λ (x y) (+ (* x x) (expt y 3))) 1 4) => ~a~%~%" ((λ (x y) (+ (* x x) (expt y 3))) 1 4)) (printf "((λ (x y) (+ (* x x) (expt y 3))) 3 8) => ~a~%~%" ((λ (x y) (+ (* x x) (expt y 3))) 3 8)) (printf "((λ (x y) (+ (* x x) (expt y 3))) -2 -2) => ~a~%~%" ((λ (x y) (+ (* x x) (expt y 3))) -2 -2)) (newline) ; ; Example 3: Write a lambda expression that takes 4 numeric arguments ; representing the (x,y) coordinates of 2 points in the plane ; and calculates the Euclidean distance between these points. ; The formula to calculate Euclidean distance between points ; (x1, y1) and (x2, y2) is (sqrt ((x1 - x2)^2 + (y1 - y2)^2)) ; ANSWER: (λ (x1 y1 x2 y2) (sqrt (+ (expt (- x1 x2) 2) (expt (- y1 y2) 2)))) ; ; Call this function on input values x1=0, y1=0, x2=4, y2=6. ; This will require only one call. (printf "((λ (x1 y1 x2 y2) (sqrt (+ (expt (- x1 x2) 2) (expt (- y1 y2) 2)))) => ~a~%~%" ((λ (x1 y1 x2 y2) (sqrt (+ (expt (- x1 x2) 2) (expt (- y1 y2) 2)))) 0 0 4 6)) ; Wait a minute! Wouldn't this whole process be simpler if we could just ; use the functions we've already written instead of repeating the ; calculations? ; ; YES! We can allow easy access to our functions as helpers, or ; subsidiary functions, inside another function by using the DEFINE ; special form to give each lambda expression a name. ; ;; Use the define special form to name the procedures you wrote in examples ;; 1-3. ; Example 1: Define a function that returns the value of its ; single numeric argument cubed. ; ANSWER: (define cube-it (λ (x) (expt x 3))) ; Call the function on the input values -3 6 2 using printf's (printf "The cube of ~a is ~a~%~%" -3 (cube-it -3)) (printf "The cube of ~a is ~a~%~%" 6 (cube-it 6)) (printf "The cube of ~a is ~a~%~%" 2 (cube-it 2)) ; Example 2: Define a function that takes 2 numeric arguments and ; returns the result of adding the square of the first ; argument to the cube of the second. ; ANSWER: (define sqX-cubeY (λ (x y) (+ (* x x) (expt y 3)))) ; Call the function on the input values x=1 y=4 and x=10 y= -10 using printf's (printf "The result of squaring ~a and adding it to the cube of ~a => ~a~%~%" 1 4 (sqX-cubeY 1 4)) (printf "The result of squaring ~a and adding it to the cube of ~a => ~a~%~%" 10 -10 (sqX-cubeY 10 -10)) ; Example 3: Define a function that takes 4 numeric arguments ; representing the (x,y) coordinates of 2 points in the plane ; and calculates the Euclidean distance between these points. ; The formula to calculate Euclidean distance between points ; (x1, y1) and (x2, y2) is (sqrt ((x1 - x2)^2 + (y1 - y2)^2)) ; ANSWER: (define distance (λ (x1 y1 x2 y2) (sqrt (+ (expt (- x1 x2) 2) (expt (- y1 y2) 2))))) ; Call this function on input values x1=0, y1=0, x2=4, y2=6, ; x1=0, y1=0, x2=1, y2=1, and ; x1=4, y1=4, x2=2, y2=2. (printf "The Euclidean distance between points (~a, ~a) and (~a, ~a) => ~a~%~%" 0 0 4 6 (distance 0 0 4 6)) (printf "The Euclidean distance between points (~a, ~a) and (~a, ~a) => ~a~%~%" 0 0 1 1 (distance 0 0 1 1)) (printf "The Euclidean distance between points (~a, ~a) and (~a, ~a) => ~a~%~%" 4 3 0 0 (distance 4 3 0 0))