meeting -*- Outline -*- Bring to class copies of the "Following the Grammar" paper. * recursively specified programs (1.2) advertisement: this is fundamental to programming interpreters (and compilers), as well as other applications (OO is like this...) ** tips for reducing time Q: What were the tips for reducing time on recursive list problems? 1. Write out your own examples if needed a. base case(s) b. related simpler example 2. What is the type? Write it down 3. Use an outline that matches the grammar for the input data type. 4. Fill in the outline by generalizing the examples a. What's returned in the base case(s)? b. How do we get the answer from - recursive call's answer, and - other information? 5. When debugging, work bottom up from subexpressions and replace recursive calls with expected results. To these we add three more: ------------------------------------------ MORE TIPS FOR SAVING TIME WHEN DOING RECURSIVE PROBLEMS 6. Assume a parser handles syntax errors in input. 7. Use helping procedures to access parts of the syntax. 8. One procedure per nonterminal. Don't mix 2 recursions in a procedure. 9. Use these tips for each procedure you write ------------------------------------------ We'll see examples in a minute ** multiple alternatives, helpers This grammar gets across the idea of helping procedures ------------------------------------------ ASSUME A PARSER ::= hot | warm | cold Parsing (parse-temperature 'hot) ==> hot (parse-temperature 'warm) ==> warm (parse-temperature 'cold) ==> cold (parse-temperature 'tepid) ~~> error (parse-temperature 23) ~~> error ------------------------------------------ These are representation dependent examples, they illustrate the current implementation. Q: So, when you have a procedure that takes a input, what can you assume about that input? ------------------------------------------ USE HELPING PROCEDURES (require (lib "temperature-mod.scm" "lib342")) Constructors: hot : (-> () temperature) warm : (-> () temperature) cold : (-> () temperature) Tests (discriminators): hot? : (-> (temperature) boolean) warm? : (-> (temperature) boolean) cold? : (-> (temperature) boolean) Comments to aid memory ::= hot "hot ()" | warm "warm ()" | cold "cold ()" ------------------------------------------ Point out production names, argument type correspondence. The use of helping procedures: - makes code easier to read - allows the parser to transform the data into some other representation. - Important in practice ------------------------------------------ FOLLOW THE GRAMMAR Problem: (make-warmer (parse-temperature 'cold)) = (warm) (make-warmer (parse-temperature 'warm)) = (hot) (make-warmer (parse-temperature 'hot)) = (hot) ------------------------------------------ Q: What's the type? (deftype make-warmer (-> (temperature) temperature)) Q: What's the outline? Q: Can you write it? (define make-warmer (lambda (temp) (cond ((cold? temp) (warm)) (else (hot))))) ** multiple nonterminals, no recursion (skip if low on time) ------------------------------------------ PHONE NUMBER GRAMMAR ::= ( . ) "phone-number (exchange subscriber)" ::= "exchange (number)" ::= "subscriber (number)" ------------------------------------------ ------------------------------------------ HELPING PROCEDURES In phone-number-mod.scm: phone-number : (-> (exchange subscriber) phone-number) exchange : (-> (number) exchange) subscriber : (-> (number) subscriber) phone-number->exchange : (-> (phone-number) exchange) phone-number->subscriber : (-> (phone-number) subscriber) exchange->number : (-> (exchange) number) subscriber->number : (-> (subscriber) number) ------------------------------------------ Point out constructors and observers. ------------------------------------------ FOR YOU TO DO Write to-string : (-> (phone-number) string) (to-string (parse-phone-number (555 . 1212))) ==> "555-1212" ------------------------------------------ (deftype to-string (-> (phone-number) string)) (define to-string (lambda (num) (string-append (to-string-exchange (phone-number->exchange num)) "-" (to-string-subscriber (phone-number->subscriber num))))) (deftype to-string-exchange (-> (exchange) string)) (define to-string-exchange (lambda (ex-num) (number->string (exchange->number ex-num)))) (deftype to-string-subscriber (-> (subscriber) string)) (define to-string-subscriber (lambda (ex-num) (number->string (subscriber->number ex-num)))) ** multiple alternatives ------------------------------------------ LAMBDA-1-EXP GRAMMAR ::= "var-exp (id)" | ( lambda ( ) ) "lambda-exp (id body)" | ( ) "app-exp (rator rand)" ------------------------------------------ The "1" comes from having 1 argument. Q: Does this look like anything familiar? ------------------------------------------ HELPING PROCEDURES FOR LAMBDA-1 var-exp? : (-> (lambda-1-exp) boolean) lambda-exp? : (-> (lambda-1-exp) boolean) app-exp? : (-> (lambda-1-exp) boolean) var-exp->id : (-> (lambda-1-exp) symbol) lambda-exp->id : (-> (lambda-1-exp) symbol) lambda-exp->body : (-> (lambda-1-exp) lambda-1-exp) app-exp->rator : (-> (lambda-1-exp) lambda-1-exp) app-exp->rand : (-> (lambda-1-exp) lambda-1-exp) var-exp : (-> (symbol) lambda-1-exp) lambda-exp : (-> (symbol lambda-1-exp) lambda-1-exp) app-exp : (-> (lambda-1-exp lambda-1-exp) lambda-1-exp) ------------------------------------------ Q: Which are tests? Constructors? Observers? point out how the names relate to the comments ------------------------------------------ RECURSION OVER LAMBDA-1 (count-var-exps (parse-lambda-1-exp 'x)) ==> 1 (count-var-exps (parse-lambda-1-exp '(x y))) ==> 2 (count-var-exps (parse-lambda-1-exp '((x z) y))) ==> 3 (count-var-exps (parse-lambda-1-exp '(lambda (x) x))) ==> 1 (count-var-exps (parse-lambda-1-exp '(f (lambda (x) x)))) ==> 2 (deftype count-var-exps (define count-var-exps (lambda (exp) ------------------------------------------ Q: Would more examples help? Q: What other questions should we ask? ... (require (lib "lambda-1-exp.scm" "lib342")) (deftype count-var-exps (-> (lambda-1-exp) number)) (define count-var-exps (lambda (exp) ;; ENSURES: result is the number of s in exp (if (var-exp? exp) 1 (if (lambda-exp? exp) (count-var-exps (lambda-exp->body exp)) (+ (count-var-exps (app-exp->rator exp)) (count-var-exps (app-exp->rand exp))))))) Write also the helping, or show them from the handout: Let's define a (set-of symbol) as a (list-of symbol) without duplicates ------------------------------------------ FOR YOU TO DO (IN PAIRS) Using the helping procedures var-exp?, lambda-exp?, var-exp->var, lambda-exp->body, app-exp->rator, app-exp->rand, set, and set-union write a procedure for: all-var-exps : (-> (lambda-1-exp) (set-of symbol)) (all-var-exps (parse-lambda-1-exp 'x)) = (set x) (all-var-exps (parse-lambda-1-exp '(x y))) = (set x y) (all-var-exps (parse-lambda-1-exp '(lambda (x) y))) = (set y) (all-var-exps (parse-lambda-1-exp '(f (lambda (x) (x (f x)))))) = (set f x) ------------------------------------------ order doesn't matter in the answers (deftype all-var-exps (-> (lambda-1-exp) (set-of symbol))) (define all-var-exps (lambda (exp) ;; ENSURES: result is a list of all the s in exp ;; (this list may contain duplicate occurrences of symbols). (if (var-exp? exp) (set (var-exp->var exp)) (if (lambda-exp? exp) (all-var-exps (lambda-exp->body exp)) (set-union (all-var-exps (app-exp->rator exp)) (all-var-exps (app-exp->rand exp))))))) Q: How would this change if we added quote to the grammar? ** combinations ------------------------------------------ STATEMENTS AND EXPRESSIONS ::= "exp-stmt (exp)" | (set! ) "set-stmt (id exp)" ::= "var-exp (id)" | "num-exp (num)" | (begin {}* ) "begin-exp (stmts exp)" where is a Scheme ------------------------------------------ Q: What are the helping procedures? Q: How does this recurse? in two places... Q: How many procedures would we use to solve a problem over this grammar? 2 ------------------------------------------ EXAMPLE PROBLEM targets : (-> (statement) (set-of symbol)) (targets (parse-statement 'x)) = (set ) (targets (parse-statement '(set! x 3))) = (set x) (targets (parse-statement '(set! x (begin (set! y 4) y)))) = (set x y) ------------------------------------------ Q: What are the base cases? Q: What other examples would be useful? Q: Any related simpler examples? Q: How many procedures? Q: What are examples for the other procedure? Write the code...