270 likes | 373 Views
Lecture 23. Pages 393-398: Separating Syntactic Analysis from Execution. We omit many details so you have to read the section in the book. The halting problem Universal machines and diagonlization. Let’s run our evaluator over factorial. (define (factorial n) (if (= n 1) 1
E N D
Lecture 23 Pages 393-398: Separating Syntactic Analysis from Execution. We omit many details so you have to read the section in the book. The halting problem Universal machines and diagonlization
Let’s run our evaluator over factorial. (define (factorial n) (if (= n 1) 1 (* (factorial- n 1) n))) The evaluator binds factorial to a procedure with Parameter n and body (if (= n 1) 1 (* (factorial- n 1) n)))
Now run (factorial 1000) The evaluator calls the body of factorial with parameter n=1000. Then there is a recursive call, and the evaluator calls the body of factorial with n=999 … Each time we call eval with the body of factorial we do syntactic analysis: We discover it is an if command, and inside it there is a (= x y) command etc. This is very wasteful: we do syntactic analysis of the same Text 1000 times.
The solution: a-eval Our evaluator (a-eval) will bind factorial to a procedure with parameter n and body. The body of the procedure will not be the text that appears in the definition of factorial, but rather a new equivalent chain of commands that reflects the syntactic parsing of factorial. Each time we call factorial (recursively or not) we will use the attached (parsed) body. The net result: Syntactic parsing is done only once.
analyze Analyze takes the command and converts it to a Code (procedure) ready to be executed. A-Eval calls the output of analyze. (define (a-eval exp env) ((analyze exp) env))
Analyze (define (analyze exp) (cond ((self-evaluating? exp) (analyze-self-evaluating exp)) ((quoted? exp) (analyze-quoted exp)) ((variable? exp) (analyze-variable exp)) ((assignment? exp) (analyze-assignment exp)) ((definition? exp) (analyze-definition exp)) ((if? exp) (analyze-if exp)) ((lambda? exp) (analyze-lambda exp)) ((begin? exp) (analyze-sequence (begin-actions exp))) ((cond? exp) (analyze (cond->if exp))) ((application? exp) (analyze-application exp)) (else (error "Unknown type - ANALYZE" exp))))
Let us go with the factorial example (define factorial (lambda (n) (if (= n 1) 1 (* (factorial- n 1) n))) (define (analyze-definition exp) (let ((var (definition-variable exp));factorial (vproc (analyze (definition-value exp))));if.. (lambda (env) (define-variable! var (vproc env) env) 'ok)))
Lambda expression (define (analyze-lambda exp) (let ((vars (lambda-parameters exp)) (bproc (analyze-sequence (lambda-body exp)))) (lambda (env) (make-procedure vars bproc env))))
Analyze-if (define (analyze-if exp) (let ((pproc (analyze (if-predicate exp))) (cproc (analyze (if-consequent exp))) (aproc (analyze (if-alternative exp)))) (lambda (env) (if (true? (pproc env)) (cproc env) (aproc env)))))
Analyzing Applications (define (analyze-application exp) (let ((fproc (analyze (operator exp))) (aprocs (map analyze (operands exp)))) (lambda (env) (execute-application (fproc env) (map (lambda (aproc) (aproc env)) aprocs)))))
Execute application (define (execute-application proc args) (cond ((primitive-procedure? proc) (apply-primitive-procedure proc args)) ((compound-procedure? proc) ((procedure-body proc) (extend-environment (procedure-parameters proc) args (procedure-environment proc)))) (else (error "Unknown type" proc))))
What bout the recursive call to factorial? Factorial is just a variable name. So we call: (define (analyze-variable exp) (lambda (env) (lookup-variable-value exp env)))
We partially open what(analyze ‘(define (factorial ..)) generates: (lambda (env) (define-variable! ‘factorial ((lambda (env) (make-procedure ‘n ; parameter (if (true? (pproc env)) ;body (cproc env) (aproc env)) env)) ;env of make-procedure env) ;aplying the lambda-exp over env env) ;env of define-variable! 'ok) We did not open the pproc, cproc, aproc..
(a-eval ‘(define (factorial ..)) generates: (define-variable! ‘factorial (make-procedure ‘n ; parameter (lambda (env) ;body (if (true? (execute-application ‘= ((lookup-variable-value ‘n env) ‘1))) ‘1 (aproc env))) env) ; env of make-procedure env)) ; env of define-variable 'ok) Notice that the body is a new sequence of commands And not the original body of factorial.
Now, when we call factorial It calls the new body, which is the result of the parsing. In particular (factorial 1000) will call factorial 1000 times, each time with the parsed sequence. The only time we parsed the original text of factorial, was when we evaluated the definition of factorial.
If we push the idea forward We get a compiler. • A compiler goes over the original code and converts it to a new code. • The compiler tries to: • Create as efficient new code as possible • Detect as many errors as possible Indeed, a-eval can serve as a basis for a Scheme compiler.
The sky is the limit (or is it?) Q: Is there any problem a Scheme program can’t solve? A: Disputes between lovers. A: What is a problem anyway? A language: A (possibly infinite) set of all the elements in {0,1}* that are within the language. A Scheme program M accepts a language L if (M x) is #true for x in L, and #false otherwise. Example: There is a Scheme program that accepts the language of all prime numbers. Q: Is there any language a Scheme program can’t recognize?
The halting problem • The halting language L: • The input is x and y. • x is interpreted as a string that defines a Scheme program Mx • (x,y) belongs to L iff Mx is a valid program and it stops on • the input y. L is a very natural language: it contains all instances of a valid Scheme program and an input that do not cause an infinite loop. Many companies will pay a lot for a program that can check whether a given program doesn’t run into an infinite loop over a given input.
Scheme can not solve the halting problem A proof: Suppose it does. So there is a Scheme program S(x,y) that accepts the halting language. • Now consider the program D (for davka): • Given an input x: • It calls S(x,x). • If the answer is #true (that is Mx stops on x) • it starts an infinite loop • Otherwise (that is Mx does not stop on x) • it stops.
Now What is the value of S(D,D) ? • If D stops on D, • then S(D,D)=#true, • then D enters an infinite loop on D, a contradiction. • If D does not stop on D, • then S(D,D)=#false, • then D stops on D, a contradiction. Conclusion: S does not exist.
I am lying now If I lied to you Then I did not lie to you If I did not lie to you Then I lied to you So, did I lie to you or not?
A Universal machine • What we did in the last few lectures shows that there is a • Scheme program U that given: • a text x in {0,1}*, and • an input y, • interprets x as a Scheme program Mx • and evaluates the output of the program Mx on the input y. The size of the program U is a fixed constant. (I estimate that it is in the order of some hundreds of lines).
Having more time helps Proof: Consider a program D(x) that: uses the universal machine (simulating only T steps) to find the value of the machine x on input x, and answers just the opposite. The running time of D is a bit over T D does not belong to Time(T). If it were than D(D) would not equal D(D)… So more time helps.
If we can diagonlize all time T machine M1…We must take more time than T.