One-Slide Summary • Building an interpreter is a fundamental idea in computing. Eval and Apply are mutually recursive . • The most complicated parts of meval are the handling of function abstraction (lambda) and function application. • The most complicated part of mapply is handling a non-primitive procedure: create a new environment, add variables to that environment corresponding to the arguments, and then apply the procedure body in that new environment. • In lazy evaluation , a value is not computed until it is Laziness needed. A thunk is a piece of code that performs a Laziness delayed computation. #2 Outline Problem Set 7 • You will be writing an interpreter for Charme • Eval – Charme is a simple version of Scheme • Apply • Your interpreter will be written in Python • Lazy • This demonstrates that Python is at least as • Thunk powerful as Scheme – Why? • It turns out that Scheme is also at least as powerful as Python – Why? #3 #4 def meval(expr, env): Conditionals if isPrimitive(expr): return evalPrimitive(expr) def evalConditional(expr, env): elif isConditional(expr): assert isConditional(expr) return evalConditional(expr, env) if len(expr) <= 2: Recall the conditional: elif isLambda(expr): evalError ("Bad ...”) (cond ((< x 5) “small”) return evalLambda(expr, env) (< x 10) “medium”) for clause in expr[1:]: elif isDefinition(expr): (< x 99) “large”))) if len(clause) != 2: evalDefinition(expr, env) evalError ("Bad ...”) elif isName(expr): predicate = clause[0] return evalName(expr, env) result = meval(predicate, env) elif isApplication(expr): if not result == False: return evalApplication(expr, env) return meval(clause[1], env) evalError ("No ...”) else: return None evalError ("Unknown expression type: " + str(expr)) #5 #6
Implementing Procedures Procedure Class class Procedure : What do we need to record? def __init__(self, params, body, env): self._params = params Environment self._body = body pointer self._env = env def getParams(self): return self._params x (+ x x) def getBody(self): Input parameters return self._body (in mouth) Procedure Body def getEnvironment(self): return self._env #7 #8 Evaluating Lambda Expressions Evaluating Applications def meval(expr, env): def evalLambda (expr,env): ... assert isLambda(expr) elif isApplication(expr): if len(expr) != 3: return evalApplication(expr, env) else: evalError ("Bad lambda ...”) evalError (...) return Procedure(expr[1], expr[2], env) meval meval mapply mapply #9 #10 evalApplication Liberal Arts Trivia: Geography def evalApplication(expr, env): • This island nation in southeast Asia is located # To evaluate an application about 20 miles off the southern coast of India. # evaluate all the subexpressions It is home to 20 million people (mostly subexprvals = map ( lambda subexpr: Sinhalese and Tamils), is a center of the meval(subexpr, env), expr) Buddhist religion, and possesses rich tropical # then, apply the value of the forests. during WWII it was used as a base for # first subexpression to the rest Allied forces against the Japanese Empire. It return mapply(subexprvals[0], subexprvals[1:]) was known as Ceylon before 1972. #11 #12
Liberal Arts Trivia: mapply Italian Literature def mapply(proc, operands): if (isPrimitiveProcedure(proc)): • This Florentine poet of the Middle Ages is called il return proc(operands) Sommo Poeta . His central work, the Divinia elif isinstance (proc, Procedure): Commedia , is often considered the greatest params = proc.getParams() newenv = ??? literary work composed in the Italian language if len(params) != len(operands): and is a masterpiece of world literature. He is evalError ("Parameter length mismatch ... ") often called the Father of the Italian Language: for i in range(0, len(params)): he wrote the Commedia in th early 14 th century in ??? a new language he called “Italian” based on the return ??? else: regional dialect of Tuscany with some Latin and evalError("Application of non-procedure: %s" % (proc)) other bits thrown in. • Bonus: Who guides him in Hell and Purgatory? #13 #14 mapply mapply def mapply(proc, operands): def mapply(proc, operands): if (isPrimitiveProcedure(proc)): if (isPrimitiveProcedure(proc)): return proc(operands) return proc(operands) elif isinstance (proc, Procedure): elif isinstance (proc, Procedure): params = proc.getParams() params = proc.getParams() newenv = Environment(proc.getEnvironment()) newenv = Environment(proc.getEnvironment()) if len(params) != len(operands): if len(params) != len(operands): evalError ("Parameter length mismatch ... ") evalError ("Parameter length mismatch ... ") for i in range(0, len(params)): for i in range(0, len(params)): ??? newenv.addVariable(params[i], operands[i]) return ??? return ??? else: else: evalError("Application of non-procedure: %s" % (proc)) evalError("Application of non-procedure: %s" % (proc)) #15 #16 Implemented mapply Interpreter! meval meval def mapply(proc, operands): if (isPrimitiveProcedure(proc)): return proc(operands) What’s missing? elif isinstance (proc, Procedure): params = proc.getParams() Special forms: newenv = Environment(proc.getEnvironment()) if, begin, set! if len(params) != len(operands): mapply mapply Primitive procedures: evalError ("Parameter length mismatch ... ") lots and lots for i in range(0, len(params)): Built-in types: newenv.addVariable(params[i], operands[i]) floating point numbers, return meval(proc.getBody(), newenv) strings, lists, etc. else: evalError("Application of non-procedure: %s" % (proc)) #17 #18
Lazy Evaluation Lazy Examples Charme> ((lambda (x) 3) (* 2 2)) • Lazy Evaluation : don’t evaluate 3 expressions until their value is really LazyCharme> ((lambda (x) 3) (* 2 2)) 3 needed Charme>((lambda (x) 3) (car 3)) (Assumes extensions – We might save work this way, since sometimes error: car expects a pair, applied to 3 from ps7) we don’t need the value of an expression LazyCharme> ((lambda (x) 3) (car 3)) 3 – We might change the meaning of some Charme> ((lambda (x) 3) (loop-forever)) expressions, since the order of evaluation no value – loops forever matters LazyCharme> ((lambda (x) 3) (loop-forever)) 3 • Not a wise policy for problem sets (all Laziness can be useful! answer values will always be needed!) #19 #20 Ordinary men and women, having the opportunity of a happy life, How do we make our will become more kindly and less persecuting and less inclined to evaluation rules lazier ? view others with suspicion. The taste for war will die out, partly for this reason, and partly because it will involve long and severe work for all. Good nature is, of all moral qualities, the one that the world needs most, and good nature is the result of ease and security, not of a life of arduous struggle. Modern methods of Original Evaluation Rule 3: Application. production have given us the possibility of ease and security for all; we have chosen, instead, to have overwork for some and To evaluate an application, starvation for others. Hitherto we have continued to be as a. evaluate all the subexpressions energetic as we were before there were machines; in this we have been foolish, but there is no reason to go on being foolish b. apply the value of the first subexpression to forever. the values of the other subexpressions. Bertrand Russell, In Praise of Idleness, 1932 (co-author of Principia Mathematica , proved wrong by Gödel’s proof) #21 #22 Liberal Arts Trivia: How do we make our Canadian Literature evaluation rules lazier ? • In this 1908 book, the title character is a talkative red-haired orphan. She moves to the village of Avonlea to live with farmers Matthew Evaluation Rule 3: Application. and Marilla Cuthbert. She becomes bosom To evaluate an application, friends with Diana Barry and has a complex a. evaluate all the subexpressions relationship with Gilbert Blythe. Her vivid b. apply the value of the first subexpression to imagination and cheerful outlook often land the values of the other subexpressions. her in trouble. • evaluate the first subexpression, and delay evaluating • Bonus: Name the setting's Canadian Province. the operand subexpressions until their values are needed. #23 #24
Recommend
More recommend