== Any Questions? == == Midterm Review == (letter grades? My first guess is that it goes by fives: 25-30 : A 20-24 : B 15-19 : C 10-14 : D 0- 9 : F) * Problem 1: let f = proc(g) letrec h (x) = if zero?(x) then 0 else (g (h -(x,1))) in h in let p = proc(i) proc(j) -(j,-(0,i)) in let i = 100 in let r = (p 3) in let m = ((p 200) i) in let n = ((f r) 2) in -(m, n) * 2 points for m's value ( only -1 for m in { -100, 400 } ) * 2 points for n's value ( only -1 for n in { 3, 9 } ) * 1 point for final subtraction * Problem 2: If-list ::= ( If-exp ) If-exp ::= Int ::= Variable ::= ifzero If-exp then If-exp else If-exp Variable = any Symbol other than if, then, or else. ((see sample solution)) ((if possible, point out that it would have been nice to have non-local control transfer, rather than having to unroll the recursive calls...)) Grading: L [1 pt] handles basic list input (e.g. '()) I [0.5 pt] detect and handle Int V [0.5 pt] detect and handle Variable (not Symbol) S [0.5 pt] some recursion *on* *sublist* T [1 pt] three recursive calls *on* *sublists* R [0.5 pt] recursive calls on sane inputs (remainders) C [1 pt] total correctness * Problem 3: (letrec ((f (lambda (a) (+ a 3))) (g (lambda (b) (let ((f (lambda (c) (+ c 5) ; line 4 )) (h (lambda (d) (+ (f d) 7)))) (list (f b) ; line 8 (h b)))))) (let ((p (lambda (m) m)) (q (lambda (n) (n (f 11))))) (append (list (f 1) (p 2) ; line 14 (q (p p))) (g 8)))) * What variables are in scope at line 4? (b c f g); 0.5 pts apiece. * What variables are in scope at line 8? (b f g h); 0.5 pts apiece. * What variables are in scope at line 14? (f g p q); 0.25 pts apiece * Problem 4: The result is (4 2 14 13 18); 1 pt for each list element * Problem 5: * [2pts] extending the grammar * [2pts] extending the value-of procedure * [1pt] total correctness * Problem 6: all points are in how you extend value-of procedure * [1pt] dispatch on let*-exp AST constructor * [1pt] recursive evaluation of binding expressions * [1pt] need to build a *new* environment * [1pt] get correct scope for let* * [1pt] total correctness - (environments are not list/pair structures!) == Specification versus Implementation == * "Specification" (American Heritage) 1. The act of specifying 2. a. A detailed, exact statement of particulars, especially a statement prescribing materials, dimensions, and quality of work for something to be built, installed, or manufactured. b. A single item or article that has been specified 3. An exact written description of an invention by an applicant for a patent. "Specification" (WordNet) 1. A detailed description of design criteria for a piece of work 2. Naming explicitly 3. (patent law) a document drawn up by the applicant for a patent of invention that provides an explicit and detailed description of the nature and use of an invention 4. A restriction that is insisted upon as a condition for an agreement (synonym: "stipulation") * "Implementation": "Implement" (American Heritage) 1. A tool or instrument used in doing work: "a gardening implement" 2. An article used to outfit or equip 3. A means of acheiving an end; an instrument or agent "Implementation" (WordNet) 1. The act of accomplishing some aim or executing some order; "the agency was created for the implementation of the policy" (synonym: "execution") 2. The act of implementing (providing a practical means for accomplishing something); carrying into effect * So enough with dictionaries; (Felix rediscovered that Computer Scientists tend to adopt terms for their own purposes). * The specification of a procedure is an precise (abstract) description of the behavior of the procedure. * The implementation of a procedure is a precise description of the behavior of the procedure. * crystal clear, right? * Here's the crucial distinction: the specification gives an abstract (hopefully high-level) *contract* that the user and the developer of a program are agreeing on. * The specification is abstract: in principle it allows for many different valid implementations, because the specification captures only the essential behavior that the client wants. * The agreement here is that the developer agrees to provide some implementation that satisfies the specification, that is, when given an acceptable input, it will produce (one of) the result(s) predicted by the specification. In return, the client agrees to avoid relying on any behavior not given in the specification. * A specification is _sufficiently_restrictive_ if it rules out all implementations that are unacceptable to an abstraction's users. * A specification is _sufficiently_general_ if it does not preclude acceptable implementations. * A specification should be _clear_ so that it easy for users (and developers) to understand. * For the most part, in this class we have been providing *algebraic* specifications, rather than *operational* ones. That *is, our specifications have usually been written as a set of *equations that our procedures are supposed to respect, without *any description of how the procedures should internally operate. == Continuations: How an expression is decomposed during evaluation == * Expressions are generally large hairy beasts. * A simple minded computer processor is not going to be able to figure out what a whole expression means in one step. It needs to *decompose* the expression into smaller pieces. * In particular, an interpreter will look at an input expression, determine what kind of expression it is, and figure out what subparts of the expression it needs to work on evaluating. * But when it starts work on a subexpression, it needs to *remember* what it was working on before it started working on the subexpression, so that when (or if) it finishes evaluating the subexpression, it knows to come back and work on the rest of the whole expression. * This is like making a TODO list. I was working on my taxes this weekend, and I determined that I had some subtasks to accomplish before I could fill out the form I was looking at. I wrote down some notes about what I was currently working on, so that when I finished the subtask, I would be able to reestablish the context of what I was doing when I encountered the need to perform the subtask in the first place. Consider the LETREC program from Problem 1 on the midterm. * When we encounter the whole thing, its this large beast that we cannot make heads or tails out of. * So we need to break down the input into smaller pieces that we can deal with individually. * Sometimes, since we are human beings and are capable of making intutive leaps of reasoning, we can see short-cuts in the evaluation. But remember that most computing systems are going to plod along in the most straight-forward manner they can. Consider -( if zero?( let x = 3 in -(x,2) ) then proc (x) (x x) else 5, 1 ) * When we see a -(E1,E2), we put aside the problem of figuring out E2 and just focus on E1. - But when we do this, we need to remember that we *were* working on -(E1,E2) - or rather, -(@,E2), where @ represents a hole where we had the expression we are currently working on. - At some point, we may figure out that the value of E1 is v1. - then we say hooray -- except we're not done. Our todo list says we still need to figure out E2. - So we put -(v1,@) on our todo list, and start working on E1. * QUESTION: when we "put aside" something like -(@,E2), can we really get away with just stashing away that structure alone? Or is there something else we need to remember? * Consider an expression like -(-(7,2),x) * What are we going to need to know when we eventually figure out that the value of -(7,2) is 5? * Consider also -( let x = 6 in -(x,1), x) * Again, what are we going to need to know when we eventually figure out that the value of let x = 6 in -(x,1) is 5? * When we see a zero?( E1 ), we remember that we need to do the zero test when we get a value back, by stashing away zero?(@), and then we focus in on E1. * When we see a let X = E1 in E2, we put aside the problem of figuring out E2 (in some environment extended with a binding for X) and just focus on E1. - But when we do this, we need to remember that we *were* working on let X = E1 in E2 - or rather, let X = @ in E2, where @ represents the hole where we had the expression we are currently working on. * When we see a (E1 E2), we put aside the problem of figuring out the whole invocation, and instead we first focus on what what E1 means, and, if the evaluation of E1 terminates, later focus on what just E2 means. - But each time, we need to remember that we *were* working on (E1 E2) - or rather, (@ E2) and (v1 @), where v1 is the value of E1. Expression/Value Env Continuation exp:let f = E1 in E2 rho_0 k_0 -> exp:proc (g) E3 rho_0 let f = @ in E2,rho_0 :: k_0 -> val:clos: let f = @ in E2,rho_0 :: k_0 -> exp:let p = E4 in E5 rho_1 k_0 -> exp:proc(i) E6 rho_1 let p = @ in E5,rho_1 :: k_0 -> val:clos: let p = @ in E5,rho_1 :: k_0 -> exp:let i = 100 in E8 rho_2 k_0 -> exp:100 rho_2 let i = @ in E8,rho_2 :: k_0 -> val:num:100 let i = @ in E8,rho_2 :: k_0 -> exp:let r = (p 3) in E9 rho_3 k_0 -> exp:(p 3) rho_3 k_1 -> exp:p rho_3 (@ 3),rho_3 :: k_1 -> val:clos: (@ 3),rho_3 :: k_1 -> exp:3 rho_3 k_2 -> val:num:3 k_2 -> exp:E6 [i=num:3]rho_1 let r = @ in E9,rho_3 :: k_0 = exp:proc (j) -(j,-(0,i)) [i=num:3]rho_1 let r = @ in E9,rho_3 :: k_0 -> val:clos: let r = @ in E9,rho_3 :: k_0 -> exp:let m = E12 in E10 rho_5 k_0 -> exp:((p 200) i) rho_5 let m = @ in E10,rho_5 :: k_0 -> exp:(p 200) rho_5 (@ i),rho_5 :: k_3 -> exp:p rho_5 (@ 200),rho_5 :: (@ i),rho_5 :: k_3 -> val:clos: (@ 200),rho_5 :: (@ i),rho_5 :: k_3 -> exp:200 rho_5 (clos: @) :: k_4 -> val:num:200 (clos: @) :: k_4 -> exp:E6 rho_6 (@ i),rho_5 :: k_3 = exp:proc(j) -(j,-(0,i)) rho_6 (@ i),rho_5 :: k_3 -> val:clos: (@ i),rho_5 :: k_3 -> exp:i rho_5 (clos: @) :: k_3 -> val:num:100 (clos: @) :: k_3 -> exp:E11 rho_7 k_3 = exp:-(j,-(0,i)) rho_7 k_3 -> exp:j rho_7 -(@,-(0,i)),rho_7 :: k_3 -> val:100 -(@,-(0,i)),rho_7 :: k_3 -> exp:-(0,i) rho_7 -(val:100,@) :: k_3 -> exp:0 rho_7 -(@,i),rho_7 :: k_5 -> val:num:0 -(@,i),rho_7 :: k_5 -> exp:i rho_7 -(num:0, @) :: k_5 -> val:num:200 -(num:0, @) :: k_5 -> val:num:-200 -(val:100,@) :: k_3 -> val:num:300 let m = @ in E10,rho_5 :: k_0 -> exp:E10 rho_8 k_0 = exp:let n = E13 in -(m,n) rho_8 k_0 -> exp:((f r) 2) rho_8 let n = @ in -(m,n),rho_8 :: k_0 -> exp:(f r) rho_8 (@ 2),rho_8 :: k_6 -> exp:f rho_8 (@ r),rho_8 :: (@ r),rho_8 :: k_6 -> val:clos: (@ r),rho_8 :: (@ r),rho_8 :: k_6 -> exp:r rho_8 (clos: @) :: k_7 -> val:clos: (clos: @) :: k_7 -> exp:E3 rho_9 k_7 = exp:letrec h (x) = E7 in h rho_9 k_7 -> exp:h rho_10 k_7 -> ... where E1 = proc(g) E3 E2 = let p = E4 in E5 E3 = letrec h (x) = E7 in h E4 = proc(i) E6 E5 = let i = 100 in E8 E6 = proc(j) -(j,-(0,i)) E7 = if zero?(x) then 0 else (g (h -(x,1))) E8 = let r = (p 3) in E9 E9 = let m = ((p 200) i) in E10 E10 = let n = ((f r) 2) in -(m,n) E11 = -(j,-(0,i)) E12 = ((p 200) i) E13 = ((f r) 2) rho_1 = [f=clos:]rho_0 rho_2 = [p=clos:]rho_1 rho_3 = [i=num:100]rho_2 rho_4 = [i=num:3]rho_1 rho_5 = [r=clos:]rho_3 rho_6 = [i=num:200]rho_1 rho_7 = [j=num:100]rho_6 rho_8 = [m=num:300]rho_5 rho_9 = [g=clos:]rho_0 rho_10 = [h=clos:]rho_9 k_1 = let r = @ in E9,rho_3 :: k_0 k_2 = (clos: @),rho_3 :: k_1 k_3 = let m = @ in E10,rho_5 :: k_0 k_4 = (@ i),rho_5 :: k_3 k_5 = -(val:100,@),rho_7 :: k_3 k_6 = let n = @ in -(m,n),rho_8 :: k_0 k_7 = (@ r),rho_8 :: k_6