290 likes | 391 Views
Lecture #9. 142-151, sections 2.3.1, 2.3.2. Symbol: a primitive type. constructors: (quote alpha) Selectors: none Methods: symbol? : anytype -> boolean eq? ; discuss in a minute (symbol? (quote x)) ==> #t. eq?.
E N D
Lecture #9 142-151, sections 2.3.1, 2.3.2 מבוא מורחב
Symbol: a primitive type constructors:(quote alpha) Selectors: none Methods:symbol? : anytype -> boolean eq? ; discuss in a minute (symbol? (quote x)) ==> #t מבוא מורחב
eq? A primitive procedure that returns #t if its two arguments are the same object (eq? (quote eps) (quote eps)) ==> #t (eq? (quote delta) (quote eps)) ==> #f (eq? (cons 1 2) (cons 1 2)) #f Eq? Can be used for any type except numbers or strings. One should use = for equality of numbers. מבוא מורחב
symboldelta symbolgamma Symbols are ordinary values In particular we can form list of symbols. (list 1 2) ==> (1 2) (list (quote delta) (quote gamma)) ==> (delta gamma) מבוא מורחב
Syntactic Sugar. Expression: Rewrites to: 1. (quote (a b)) (list (quote a) (quote b)) 2. (quote ()) nil 3. (quote (1 (b c))) (list (quote 1) (quote (b c))) (list 1 (quote (b c))) (list 1 (list (quote b) (quote c))) (1 (b c)) 4. 'a is shorthand for(quote a)'(1 (b c))(quote (1 (b c))) מבוא מורחב
Your turn: (define a 2) (define b 5) (+ a b) ==> '(+ a b) ==> (+ 'a b) ==> (list '+ a b) ==> (list + ‘a b) ==> (eq? '(cons 1 2) '(cons 1 2)) #f 7 (+ a b) ([proc#..] a 3) - error (+ 2 5) ([procedure #…] a 5) מבוא מורחב
Summary so far • symbol is a primitive type • the special form quote is its constructor • quoting the same name always returns the same object • the primitive procedure eq? tests for sameness מבוא מורחב
Manipulating lists and trees of symbols מבוא מורחב
Example 1: memq If item does not appear in x, returns false Otherwise – returns the sublist beginning with item (define (memq item x) (cond ((null? x) #f) ((eq? item (car x)) x) (else (memq item (cdr x))))) (a b c) (memq 'a '(b a b c)) => (memq 'a '((a b) b c)) => (memq 'a ‘((a b) b a (c a) d)) => #f (a (c a) d) מבוא מורחב
Example 2: rember Removes the first occurrence of item in x. (define (rember item x) (cond ((null? x) ‘()) ((eq? item (car x))(cdr x)) (else (cons (car x) (rember item (cdr x)))))) (d b c a) (rember 'a '(d a b c a)) => (rember 'b '(a b c)) => (rember 'a '(b c d)) => (a c) (b c d) מבוא מורחב
Example 3: rember* Recursively removes all occurances of a (define (rember* a x) (cond ((null? x) ‘()) ((atom? (car x)) (cond ((eq? (car x) a)(rember* a (cdr x))) (else (cons (car x) (rember* a (cdr x)))))) (else (cons (rember* a (car x)) (rember* a (cdr x)))))) (rember* 'a '(a b)) => (rember* 'a '(a (b a) c (a)) => (b) ((b) c ())
An example: symbolic differentiation מבוא מורחב
Symbolic differentiation (deriv <expr> <with-respect-to-var>) ==> <new-expr> The expressions we deal with: x+y x+5 2x (x+5) + 2 x y • (deriv '(+ x 3) 'x) ==> 1 • (deriv '(+ (* x y) 4) 'x) ==> y • (deriv '(* x x) 'x) ==> (+ x x) מבוא מורחב
Step 1: Legal expressions. First we have to choose what expressions we work with, And how we represent them. Suppose we allow addition and multiplication. Do we accept x+y or (+ x y) ? What about x+y+z and (+ x y z) ? Do we interpret x+ y * z as (x+y)*z or as x+(y*z) ? How do we represent the output? Are we trying to simplify the output. מבוא מורחב
Step 1: Legal Expressions- formal Expr = SimpleExpr | CompoundExpr SimpleExpr = number | symbol CompoundExpr = LIST( OPERATOR, Expr, Expr ) Operator = +|* מבוא מורחב
Step 2: Breaking the problem to smaller subproblems • Base case: (corresponds to SimpleExpr) • deriv constant dx = 0 • deriv variable dx = 1 if variable is the same as x = 0 otherwise • Induction step: (corresponds to CompoundExpr) • (f+g)’ = f’ + g’ • (f*g)’ = f * g’ + g * f’ מבוא מורחב
Step 3: An algorithm assuming an abstract interface. (define deriv (lambda (expr var) (cond ((number? expr) 0) ((variable? expr) (if (eq? expr var) 1 0)) ((sum-expr? expr) (make-sum (deriv (addend expr) var) (deriv (augend expr) var))) ((product-expr? expr) (make-sum (make-product (augend expr) (deriv (addend expr) var)) (make-product (addend expr) (deriv (augend expr) var))) (else (error "unknown expression" expr)))) מבוא מורחב
Step 4: The underlying interface Constructors: make-product make-sum Methods: number? variable? sum-expr? product-expr? Selectors: addend augend מבוא מורחב
We represent constants with integers. We represent symbols with (quote ..) Step 5: The underlying interface – constructors and selectors. We define the constructors: (define (make-sum e1 e2) (list '+ e1 e2)) (define (make-product e1 e2) (list '* e1 e2)) And the selectors: (define (addend expr) (cadr expr)) (define (augend expr) (caddr expr)) מבוא מורחב
Step 5: The underlying interface – methods. (define (sum-expr? expr) (and (pair? expr) (eq? (car expr) '+))) (define (product-expr? expr) (and (pair? expr) (eq? (car expr) ‘*))) (define (variable? expr) (and (not (pair? expr)) (symbol? expr))) מבוא מורחב
Writing, Debuging, Testing… (deriv 5 ‘x) 0 (deriv ‘x ‘x) 1 (deriv ‘x ‘y) 0 … (deriv ‘(+ x y) ‘x) (+ 1 0) (deriv ‘(+ x y) ‘z) (+ 0 0) (deriv '(* (+ x y) (- x y)) 'x) unknown expression (- x y) (deriv '(* (+ x y) (+ x (* -1 y))) 'x) (+ (* (+ x (* -1 y)) (+ 1 0)) (* (+ x y) (+ 1 (+ (* y 0) (* -1 0))))) מבוא מורחב
We would like to simplify expressions. Instead of the expression (+ (* (+ x (* -1 y)) (+ 1 0)) (* (+ x y) (+ 1 (+ (* y 0) (* -1 0))))) We would like to have 2x What should we change? How easy is it to make the change? מבוא מורחב
We change make-sum and make-product (define (make-sum a1 a2) (cond ((and (number? a1) (= a1 0)) a2) ((and (number? a2) (= a2 0)) a1) ((and (number? a1) (number? a2)) (+ a1 a2)) (else (list '+ a1 a2)))) (define (make-product a1 a2) (cond ((and (number? a1) (= a1 0)) 0) ((and (number? a2) (= a2 0)) 0) ((and (number? a1) (= a1 1)) a2) ((and (number? a2) (= a2 1)) a1) ((and (number? a1) (number? a2)) (* a1 a2)) (else (list ‘* a1 a2)))) It’s easier to change a well-written code. מבוא מורחב
Testing again.. (deriv '(* (+ x y) (+ x (* -1 y))) 'x) (+ (+ x (* -1 y)) (+ x y)) This is an improvement. There is still a long way to go…. מבוא מורחב
Allowing (- x y) (define (make-minus a1 a2) (cond ((and (number? a1) (= a1 0)) a2) ((and (number? a2) (= a2 0)) a1) ((and (number? a1) (number? a2)) (+ a1 a2)) (else (list ‘- a1 a2)))) (define (minus-expr? expr) (and (pair? expr) (eq? (car expr) ‘-))) מבוא מורחב
Allowing x^k, …. ,1/x, (ln x) (define (ln-expr? expr) (and (pair? expr) (eq? (car expr) ‘ln))) (define deriv (lambda (expr var) (cond … ((minus-expr? expr) … ((ln-expr? expr) … )..) מבוא מורחב
Allowing (+ x y z … w) (* x y z … w) How about the following change: (define (addend expr) (cadr expr)) (define (augend expr) (let ((first (car expr)) (second (cadr expr)) (rest (cddr expr))) (cond ((> (length rest) 1) (cons first rest)) ((= (length rest) 1) (car rest))))) מבוא מורחב
Testing.. > (deriv '(+ x y z w a b c x y z e r t ) 'y) 2 > (deriv '(+ x y z w a b c x y z e r t ) 'f) 0 > (deriv '(* x y z w x t y ) 't) (* x (* y (* z (* w (* x y))))) > (deriv '(* x y z w x t y) 'x) (+ (* y z w x t y) (* x (* y (* z (* w (* t y)))))) מבוא מורחב
Guidelines • Carefully think about • the problem • type of data • The algorithm. • Identify • Constructors • Selectors, • And the methods you need from your data. • Use data abstractions. • Respect abstraction barriers. • Avoid nested if expressions, complicated procedures and always use good names. מבוא מורחב