This lab focuses on "faking" nonstrict evaluation of function parameters in Lisp, by passing in lambda-expressions with no parameters and using "apply" to evaluate them (you can also use Lisp's "eval" function if you are familiar with that). From this point on, I will refer to a lambda-expression with no parameters as a "thunk" (this may not be exactly the right use of the word "thunk", but it is at least close).
The basic idea is that we're going to make a working version of the following functions, which do not work in Lisp because Lisp uses strict evaluation for functions:
(defun broken-myif
(condition true-value false-value)
(if condition true-value false-value))
(defun broken-power (base exponent)
(broken-myif (= exponent 0)
1
(* base (broken-power base (- exponent 1)))))
Write the functions for Question 1-3 in a file lab9.lisp in your simple-funcs project, and answer questions 4 and 5 on paper and hand them in.
1) Create a function "lazy" that takes one argument (which will be a "thunk") with and returns the value of the thunk.
Thus,
(lazy #'(lambda () (+ 2 3)))
should produce 5, as should
(let ((x 3)) (lazy #'(lambda () (+ 2 x)))).
2) Create a function "myif" that takes three thunks, and acts like "if" - that is, it returns the value of the third thunk if the value of the first is (), and returns the valuen of the second thunk otherwise (remember that lisp uses the empty list as "false").
Thus, we should get 7 as the result of the expression
(let ((x ())) (myif #'(lambda () x) #'(lambda () 5) #'(lambda () 7)))
and 5 if we let x be t (which is often used for true) or 17, or anything other than ().
3) Use your "myif" function to create a function named "power" to raise a number to a nonnegative integer power.
4) Draw a "call tree" showing what functions are called in each function call during the evaluation of (power 2 3). This is different from your stack diagrams from lab 7, since those were supposed to show only the functions that were "active" at a given point, but included information about access links and other stuff that is set up by the system. This "call tree" picture should be a tree in which there is a node for every function call that is made (showing the function name and arguments) and node X is the parent of Y if Y is called from X. If X makes calls Y and then Z, Y and Z should both be children of X - put X to the left of Z since it happens first.
5) Must a function that has no side effects (that is, it returns a value but does not change anything other than local variables) necessarily be "referentially transparent"? If it must, explain why; if not, give a counter example.