CSE 305 Introduc0on to Programming Languages Lecture 10 – Applica0on of Lambda Calculus – LISP/Scheme CSE @ SUNY-­‐Buffalo Zhi Yang Courtesy of Professor Michael Genesereth Courtesy of Dr. David Reed Courtesy of Professor Marek A. Perkowski NoGce Board • First, June 25, 2013, we will be having a review class. • Second, the second long quiz taken today will be discussed aSer the review class menGoned above. Our objecGve • The first objecGve of our class, is to comprehend a new programming language within very short 0me period, and because you have this ability to shorten your learning curve, you are going to manipulate the language with an insight learning. • The second objecGve is to even engineer your own language! Review what we ve learnt and see future eg: EgypGan Number System; Complement Number eg: Abacus Number System eg: Gate system, Including different underline device 1st GeneraGon language: Machine Code eg: MIPS 2nd GeneraGon language: Assembly Code eg: Fortran Regular Expression What s next ? 3rd GeneraGon Language: Macro funcGon Macro func0on Basic CalculaGon System Lexer Compiler System Virtual Machine Parser Push Down Automata Type Checking Context-­‐Free Grammar Lambda Calculus Theory Data Atoms Lisp Data Types: Types: Atom • There are two: atoms and lists. • Atoms: a, 7, tom, my-age, nil, T – Evaluate an atom gives the value assigned that atom. Numbers are special--they always evaluate to themselves. 7 => 7 my-age => Error (variable not defined) – Assign a value to an atom with setq and/or setf (setq my-age 24) => 24 my-age => 24 – Reserved: nil and T nil => nil t => t – Case insensitive: aBc and ABC are the same atom Data Types: LISP Data Types: LLists ists • Lists: (a), (+ 6 7), (a (e f g) h), (), nil – nil is both an atom and a list. It is equivalent to the empty list: (). – Evaluating a list always invokes a function. (function-name arg1 … argn) (+ 6 7) => 13 (foo 17 18 19) => Error (function not defined) (+ my-age 4) => 28 – When evaluating a list, first evaluate all the arguments and then apply the function to all those results. Evaluate := compute/fetch value of an expression Form := an expression to be evaluated A number evaluates to itself: > 76 => 76 A variable evaluates to its value: > (seh x 54) > x => 54 A quoted symbol evaluates to the symbol itself: > z => z A string evaluates to itself: > portland => portland A single quoted list evaluates to a simple list of symbols > (a b c) => (a b c) > (+ 2 3) => (+ 2 3) An unquoted list evaluates to a funcGon call > (+ 2 3) => 5 > (a b c) => ERROR: alempt to call an undeclared funcGon a Evaluate arguments leS-­‐to-­‐right, then call funcGon: > (seh bob 5 bill 7 sue 9) > (+ bob bill sue) => 21 ;; (Calls + with 3 values: 5, 7, 9) Polish notaGon: (operator operand1 operand2 … operandn) (+ 2 3 4 5) simpler than 2 + 3 + 4 + 5 + 6 if you can live with all the parentheses!! Parentheses => no need for arithmeGc precedence rules > (+ (* a b) (* c d)) -­‐vs-­‐ a*b + c*d PrimiGve FuncGons Primitive Functions 1 • Lisp includes many built-in functions: +, *, -, /, max, min, sqrt • More importantly, includes built-in list operations. – cons builds a list out of data and a tail. (cons 1 nil) => (1) (cons 1 (cons 2 nil)) => (1 2) – Notice the tail value signifying ‘nothing’ is nil. – Now try using it with atoms that are not reserved. (cons a nil) => Error: variable a is not defined. • Why does this give an error? Primitive Functions: Lists PrimiGve FuncGons: BBuilding uilding Lists • We need to tell the interpreter not to evaluate the atom a. To do that, we use ‘. (cons ‘a nil) => (a) • ‘ can also be applied to an entire list (cons ‘a ‘(b c d)) => (a b c d) • cons can be irritating: make a list of ‘a, ‘b, ‘c, and ‘d without quoting a list. – list and append are functions that take any number of arguments: (list ‘a ‘b ‘c ‘d) => (a b c d) (list ‘a ‘(b c d)) => (a (b c d)) (append ‘(a b c) ‘(d e f) ‘(g h i)) => (a b c d e f g h i) Backquote nd C omma Backquote aand Comma • Sometimes we want to quote a list except for one or two of its members, e.g. (list ‘a ‘1 (/ my-age 2) ‘b ‘4) => (a 1 12 b 4) • Backquote and comma allow us to write the above without so many quotes: `(a 1 ,(/ my-age 2) b 4) – Thus the comma within a backquote tells Lisp to evaluate what follows. That is just the opposite of what the ‘ function does normally. Primitive Functions: Accessing PrimiGve FuncGons: Accessing Lists Lists • Once a list is built, how do we access its members? – first and car give you the first element of a list. (first ‘(1 2 3)) => 1 (first ‘((a b) 2 3)) => (a b) – last and cdr give you the list minus the first element. (rest ‘(1 2 3)) => (2 3) (rest ‘((a b) 2 3)) => (2 3) – car and cdr can be combined (caar ‘((a b) c d e)) (cdar ‘((a b) c d e)) => a => (b) Work from the right to the left Changing Atom Values Changing Atom Values • Example (setq mylist ‘(b c d)) => (b c d) (cons ‘a mylist) => (a b c d) mylist => (b c d) • No side effects! (for the most part) – Need to setq to change an atom’s value. • setf is a version of setq that takes a function as its first argument. (setf (cadr mylist) 7) => 7 mylist => (b 7 d) Changing Atom Values Changing Atom Values • Example (setq mylist ‘(b c d)) => (b c d) (cons ‘a mylist) => (a b c d) mylist => (b c d) • No side effects! (for the most part) – Need to setq to change an atom’s value. • setf is a version of setq that takes a function as its first argument. (setf (cadr mylist) 7) => 7 mylist => (b 7 d) SETF (seh y (+ 3 5)) => y assigned the value 8 (seh y ((a 1) (b 2) (c 3))) => y assigned to the data list * Can be used to set arbitrary locaGons in Lisp data structures (seh (second y) 88) => 88 y => ((a 1) 88 (c 3)) SETQ (seh x (+ 3 5)) => x assigned the value 8 * First argument must be a symbol, not a general locaGon. Access AnyGme a variable appears, it will be evaluated (i.e. its value will be accessed), unless the variable appears inside the scope of a single or double quote, or is an argument to a macro. > x => 8 > x => x Sets Sets • Can treat lists as sets (order not preserved) (union ‘(a b) ‘(a d)) => (a b d) (union ‘((a) (b)) ‘((a))) => ((a) (b) (a)) (union ‘((a) (b)) ‘((a)) :test #’equal) => ((a) (b)) – The test condition for determining whether 2 items in the set are the same is the function equal. (adjoin ‘a ‘(a b c)) => (a b c) (set-difference ‘(a b c) ‘(b d c)) => (a) • adjoin and set-difference can use :test #’equal as well. Can even supply your own function (once we show you how to define one). More FuncGons More functions • • • • • (length ‘(a b c)) => 3 (atom ‘a) => T (atom ‘(a b c)) => NIL (listp ‘a) => NIL (listp ‘(a b c)) => T Representing KIF Sentences RepresenGng KIF Sentences • KIF sentences: (<= p (and q r)) (not (not q)) (or r (not s) t) • How do we represent these in Lisp? – Simple--use lists. (list ‘<= ‘p (list ‘and ‘q ‘r)) (list ‘not (list ‘not ‘q)) (list ‘or ‘r (list ‘not ‘s) ‘t) • What about the empty clause? • Notice the KIF operators =>, <=, <=>, or, and, not will always be the first element of the list. Defining functions Defining funcGons • (defun <name> <documentation-string> (<arguments>) <body>) (defun square “computes square” (x) (* x x)) (defun ar (premises conclusion) nil) • Note that we need not quote any of the arguments to defun. It is taken care of automatically. • Evaluating a function for some set of arguments results in the last expression evaluated in the function trace. Branching Branching • (if <expr> <then-expr> <else-expr>) (if (> x y) (- x y) (- y x)) • (cond ((testa) (form1a) (form2a)…(formNa)) ((testb) (form1b)…(formNb)) … (t (form1k) … (formNk)) (cond ((atom p) nil) ((listp p) (car p)) (t nil)) • Evaluating cond evaluates the tests until one evaluates to true. It then evaluates each of the appropriate forms. The last evaluation is the value of the entire cond function. Logical Functions and Null Logical FuncGons and Null • (and <form1> <form2> … <formn>) – Evaluates to nil as soon as one of <formi> is nil. Otherwise evaluates to <formn> • (or <form1> <form2> … <formn>) – Evaluates to first non-nil argument. If there are none evaluates to nil. • (not <form>) and (null <form>) are identical. Usually use the latter when the result should be a list. – Evaluate to T iff <form> is nil. (not (+ 1 2 3)) => Nil (not (and (eq (+ 1 2) 3) (< 4 3) (/ 5 0))) => T Iteration IteraGon • (let ((<var1> <init1>) (<var2> <init2>) …) <body> ) – Declares local variables. It is best to declare variables before using them. • (dotimes (<counter> <limit> <result>) <body>) (let ((sum 0)) (dotimes (i 10 sum) (setq sum (+ sum i))) ) => 45 IteraGon2 Iteration2 • (dolist (<var> <initlist> <result) <body>) (let ((sum 0)) (dolist (i ‘(1 2 3) sum) (setq sum (+ sum i)) )) => 6 • (do ((<var1> <init1> <increment1>) (<var2> <init2> <increment2>) …) (<termination-test> <result>) <body>) – Combines let and dolist Example Example (defun positive-literals (clause) (cond ((atom clause) nil) ((listp clause) (do ((cs clause (cdr cs)) (poslist nil)) ((null cs) poslist) (if (pos-litp (car cs)) (setq poslist (cons (car cs) poslist)) ))))) • Result of (positive-literals ‘(or p (not q) (not s))) ? Recursion Recursion • Nothing new here. (defun power (base exp) (if (eq exp 0) 1 (* base (power base (- exp 1))) )) (power 3 2) => 9 • Efficiency • user-­‐reverse res is opGonal argument Argument list Mapcar Mapcar • (mapcar <function-name> <list>) – mapcar applies the function to each element of list and returns a list of the results. (mapcar ‘atom ‘(1 2 (a b) 3)) => (T T nil T) (defun times2 (x) (* x 2)) => times2 (mapcar ‘times2 ‘(2 3 4)) => (4 6 8) • Other List operations: remove-if, remove-if-not, some, every, search, subseq, length Strings Strings • A string in Lisp is technically an array of characters (just like C). • You’ll need to use special operators to work with strings: concatenate, subseq, search. • The sample code includes enough functionality so that you should not need to worry about strings besides outputting the results of your reasoner. • The only thing to watch out for is when you are including a quote in the html you send back to the client. Just make sure you use a \ to escape any such quotes. An example appears in the function myfrontpage. Output Output • (print <form>) both prints the evaluation of <form> and returns the evaluation of <form>. • Useful for debugging • princ, print1, print all work the basically the same but with minor differences. Formatted Output Formaled Output • (format <destination> <control-string> <optionalarguments>) – <destination>: t prints to the command line nil prints nothing but returns string else prints to the stream <destination> – <control-string>: much like printf/sprintf in C. Includes placeholders for arguments. – <optional-arguments>: Arguments that fill in the placeholders in the control-string Formatted Output Formaled Output 2 2 (format t “7 * 6 = ~A” (* 7 6)) 7 * 7 = 42 => NIL (format nil “~A” ‘(a b c)) => “(a b c)” ~A: Ascii--any Lisp object MIPS ~D: Decimal--numbers Assembly Language Programmer’s MIPS Guide ~%:Language newline Assembly Programmer’s Guide ~~: tilde ASM-01-DOC ASM-01-DOC Debugging:trace trace Debugging: • (trace <func-name1> <func-name2> … <funcnamen>), e.g. (trace times2 positive-literals) – Every time one of these functions is evaluated, Lisp prints out the function name and the arguments it was given to the terminal. Every time one of these functions exits, Lisp prints out what its return value was. – Calling trace multiple times will add to the list of functions. • To turn off tracing for a function foo and bar, use (untrace foo bar) • To turn off all tracing, use (untrace) List Constructors CONS ( construct ) (cons a (a b c)) => (a a b c); (cons (a b) (c d)) => ((a b) c d) (cons a nil) => (a); (cons nil (a b)) => (nil a b)) = (() a b) LIST (list a b) => (a b); (list (a b) c d) => ((a b) c d) APPEND (append (a b c) (d e f)) => (a b c d e f); (append nil (a b)) => (a b) These are not destruc+ve: > (seh x (a b c)) > (cons 62 x) => (62 a b c) > x => (a b c) • Execu0on of cons • • • • Recursion count-­‐atoms null cond • Op0onal arguments OpGonal argument (root 4)==>2 (root 4 3)==>4 1/3 Binds to the cdr of list of arguments Binds to the car of list of arguments • Internal List Representa0on • Free Storage List • equal • eq Two pointers point to the same locaGon • Garbage collec0on How one LISP sentence is parsed ? • (f1 (f2 a (f3 b)) c 8 (f2 3 2)) f1 c f2 a f3 b 8 f2 3 2 Destruc0ve List Modifiers (1) PUSH/POP: treat list like a stack and alter symbol values ( destruc0ve ) > (push 77 x) => (77 a b c) > x => (77 a b c) > (pop x) => 77 > x => (a b c) REVERSE (non-­‐destrucGve) (reverse (a b c)) => (c b a) ; (reverse ((a 1) (b 2))) => ((b 2) (a 1)) NREVERSE (destruc0ve reverse => no copying, but use seh for safety) > (seh x '(a b c)) => (a b c) > (nreverse x) => (c b a) > x => (a) > (seh x '(a b c)) => (a b c) > (seh x (nreverse x)) => (c b a) > x => (c b a) List Modifiers (2) SETF + List Accessors (Destruc0ve!): > (seh y '(a b c)) => (a b c) > (seh (second y) 23) => 23 > y => (a 23 c) > (seh (second (cdr y)) 99) => 99 > y => (a 23 99) > (seh (cdr y) '(aaa bbb ccc)) => (aaa bbb ccc) > y => (a aaa bbb ccc) Cons Cells > (seh x (ntnu idi lade)) => (ntnu idi lade) > (seh y (cons trondheim x)) => (trondheim ntnu idi lade) > (seh z (cons (1 2 3) y)) => ( (1 2 3) trondheim ntnu idi lade) z 1 2 3 Shared area y trondheim x ntnu idi lade = cons cell (standard lisp terminology) or box (Winston) *Each call to cons uses one new cons cell and sets car to first elem, cdr to 2nd. List Crea0on > (seh x (a b c)) ;; Uses 3 newcons cells ; same as (seh x (list a b c)) > (seh y (1 2 3)) ;; Uses 3 more new cons cells; same as (seh y (list 1 2 3)) > (seh z (list x y the end)) ;; Uses 4 more new cons cells z end the y 1 2 3 x a b c Cons cells in memory Memory (seh x (ntnu idi lade 639)) FFE073: Symbol Table AAA050: ntnu value: unbound AAA150: idi value: unbound AAA250: lade value: unbound AAA050 FFF101 1-­‐byte data type pointer 4-­‐byte to cell s value 4-­‐byte pointer to next cons cell FFF101: AAA150 FFF252 x value: FFE073 *Cons cells, symbol table and regular data storage are all in memory *Each symbol has many possible properGes in the symbol table FFF252: FFF849: AAA250 FFF849 CCC250 000000 Simple Data Storage CCC250: 639 • Non-­‐Destruc0ve List Opera0ons Many beginners do this mistake They think about variables as separate containers APPEND > (seh x (ntnu idi lade)) > (seh y (1 2 3)) x > (seh z (append x y)) > z (ntnu idi lade 1 2 3) > x (ntnu idi lade) ntnu idi lade 1 2 3 z *Copies all of x s cons cells, so x is unchanged. copied shared y • More on Destruc0ve List Opera0ons NCONC is destruc0ve opera0on!!!!!! • Destruc0ve Lisp Opera0ons SETF is destruc0ve opera0on!!!!!! SETF is can cause infinite printout loop!!!!! NCONC (Destruc0ve Append) (nconc list1 list2…listn) -­‐ changes next ptr in the last cons cells of list1 -­‐ listn-­‐1 (seh x (ntnu idi lade) y (1 2 3)) (seh z (nconc x y)) > z (ntnu idi lade 1 2 3) > x x (ntnu idi lade 1 2 3) NCONC is destruc0ve APPEND !!!!! z ntnu idi lade 2 3 y DestrucGve funcGon => some of the 1 original arguments may be changed RPLACA = (SETF (FIRST ..)) SETF can make destrucGve modificaGons to lists. > (seh x (a b c)) > (seh y x) y > (seh (first y) 99) > y (99 b c) x > x (99 b c) > (seh (nth 2 y) 88) > x (99 b 88) 99 > (rplaca y 55) a > x 55 (55 b 88) b RPLACA is destruc0ve !!!!! c 88 RPLACD = (SETF (REST ..)) y RPLACD is destruc0ve !!!!! x > (seh x (a b c)) > (seh y x) > (seh (rest y) (22 33)) > x (a 22 33) > (rplacd y (77 88)) > x (a 77 88) a *There are no remaining pointers to (b c) nor (22 33). Their cons cells should be freed up for cons and list to reuse. This is, they should be garbage collected. LISP has automaGc garbage collecGon. b 22 77 c 33 88 List Parameters in Func0on Calls (1) • LISP uses call by value for all parameters. • In the case of lists, this means that the formal parameters get a copy of the pointer to the list, not a copy of the whole list. (defun change1 (list) (seh (first list) (first (last list)))) (defun change2 (list) (cons (first (last list)) (rest list))) x value: a > (sea x (a b c)) change1 list: b change 2 list: c List Parameters in Func0on Calls (2) SETF is destruc0ve !!!!! > (seh x (a b c)) > (change1 x) * Change1 uses seh(first..), which is destrucGve. So x changes also. x value: a change1 list: c b c (defun change1 (list) (seh (first list) (first (last list)))) (defun change2 (list) (cons (first (last list)) (rest list))) List Parameters in Func0on Calls (3) CONS is not destruc0ve !!!!! > (seh x (a b c)) > (change2 x) * Change2 uses cons, which is non-­‐destruc0ve. So x is unchanged. x value: a b c (defun change1 (list) (seh (first list) (first (last list)))) (defun change2 (list) (cons (first (last list)) (rest list))) change2 list: c Scheme: Lisp dialect • Syntax (slightly simplified): expression → atom | list atom → number | string | iden7fier | character | boolean list → '(' expression-­‐sequence ')' expression-­‐sequence → expression expression-­‐sequence | expression • Everything is an expression: programs, data, … Thus programs are executed by evaluaGng expressions. • Only 2 basic kinds of expressions: – atoms: unstructured – lists: the only structure (a slight simplificaGon). Expressions 42 "hello" #T #\a (2.1 2.2 3.1) hello (+ 2 3) (* (+ 2 3) (/ 6 2)) —a number —a string —the Boolean value "true" —the character 'a' —a list of numbers —a idenGfier —a list (idenGfier "+" and two numbers) —a list (idenGfier "*" and two lists) EvaluaGon of Expressions Programs are executed by evaluaGng expressions. Thus semanGcs are defined by evaluaGon rules of expressions. EvaluaGon Rules: • number | string: evaluate to itself • IdenGfier: looked up in the environment, i.e., dynamically maintained symbol table • List: recursively evaluate the elements (more details in following slides) Eager EvaluaGon • A list is evaluated by recursively evaluaGng each element: • unspecified order • first element must evaluate to a funcGon. This funcGon is then applied to the evaluated values of the rest of the list. (prefix form). E.g. 3 + 4 * 5 (a == b)&&(a != 0) gcd(10,35) (+ 3 (* 4 5)) (and (= a b) (not (= a 0))) (gcd 10 35) • Most expressions use applicaGve order evaluaGon (eager evaluaGon): subexpressions are first evaluated, then the expression is evaluated. (correspondingly in imperaGve language: arguments are evaluated at a call site before they are passed to the called funcGon.) Lazy EvaluaGon: Special Forms • if funcGon (if a b c): – a is always evaluated – Either b or c (but not both) is evaluated and returned as result. – c is opGonal. (if a is false and c is missing, the value of the expression is undefined.) e.g., (if (= a 0) 0 (/ 1 a)) • cond : (cond (e1 v1) (e2 v2) ... (else vn)) – The (ei vi) are considered in order – ei is evaluated. If it is true, vi is then evaluated, and the value is the result of the cond expression. – If no ei is evaluated to true, vn is then evaluated, and the value is the result of the cond expression. – If no ei is evaluated to true, and vn is missing, the value of the expression is undefined. (cond ((= a 0) 0) ((= a 1) 1) (else (/ 1 a))) Lazy EvaluaGon: Special Forms • define funcGon: declare idenGfiers for constants and funcGon, and thus put them into symbol table. (define a b): (define (a p1 p2 …) b1 b2 …): with parameters p1 p2 …. define a name define a funcGon a the first expression aSer define is never evaluated. e.g., – define x (+ 2 3) – (define (gcd u v) (if (= v 0) u (gcd v (remainder u v)))) Lazy EvaluaGon: Special Forms • Quote, or ' for short, has as its whole purpose to not evaluate its argument: (quote (2 3 4)) or '(2 3 4) returns just (2 3 4). (we need a list of numbers as a data structure) • eval funcGon: get evaluaGon back (eval '(+ 2 3)) returns 5 Other Special Forms • let funcGon: create a binding list (a list of name-­‐value assocaGons), then evaluate an expression (based on the values of the names) (let ((n1 e1) (n2 e2) …) v1 v2 …) e.g., (let ((a 2) (b 3)) (+ a b)) • Is this assignment? Lists List – Only data structure – Used to construct other data structures. – Thus we must have funcGons to manipulate lists. • cons: construct a list (1 2 3) = (cons 1 (cons 2 (cons 3 '()))) (1 2 3) = (cons 1 '(2 3)) • car: the first element (head), which is an expression (car '(1 2 3)) = 1 • cdr:the tail, which is a list (cdr '(1 2 3)) = (2 3) Data structures (define L (car (car (cdr (car (car (car Note: '((1 2) 3 (4 (5 6)))) L)) L)) (cdr (cdr L)))) car(car = caar cdr(car = cdar car(car(cdr(cdr = caaddr Box diagrams a List = (head expression, tail list) • L = ((1 2) 3 (4 (5 6))) looks as follows in memory L 3 1 2 4 5 6 Other list manipulaGon operaGons: based on car, cdr, cons • (define (append L M) (if (null? L) M (cons (car L) (append (cdr L) M)) ) ) • (define (reverse L) (if (null? L) M (append (reverse (cdr L)) (list (car L))) ) ) Lambda expressions /funcGon values • A funcGon can be created dynamically using a lambda expression, which returns a value that is a funcGon: (lambda (x) (* x x)) • The syntax of a lambda expression: (lambda list-­‐of-­‐parameters exp1 exp2 …) • Indeed, the "funcGon" form of define is just syntacGc sugar for a lambda: (define (f x) (* x x)) is equivalent to: (define f (lambda (x) (* x x))) FuncGon values as data • The result of a lambda can be manipulated as ordinary data: > ((lambda (x) (* x x)) 5) 25 > (define (add-x x) (lambda(y)(+ x y))) > (define add-2 (add-x 2)) > (add-2 15) 17 Higher-­‐order funcGons • higher-­‐order funcGon: a funcGon that returns a funcGon as its value or takes a funcGon as a parameter or both • E.g.: • add-x • compose (next slide) Higher-­‐order funcGons (define (compose f g) (lambda (x) (f (g x)))) (define (map f L) (if (null? L) L (cons (f (car L))(map f (cdr L))))) (define (filter p L) (cond ((null? L) L) ((p (car L)) (cons (car L) (filter p (cdr L)))) (else (filter p (cdr L))))) let expressions as lambdas: • A let expression is really just a lambda applied immediately: (let ((x 2) (y 3)) (+ x y)) is the same as ((lambda (x y) (+ x y)) 2 3) • This is why the following let expression is an error if we want x = 2 throughout: (let ((x 2) (y (+ x 1))) (+ x y)) • Nested let (lexical scoping) (let ((x 2)) (let ((y (+ x 1))) (+ x y))) Memory management in Scheme • all data is dynamically allocated (heap-­‐based) – variables (from funcGon definiGons, let-­‐expressions) may be stored on stack • underlying lists is the doled-­‐pair structure (a b c) ≡ a (a . (b . (c . ()))) this structure demonstrates b c § non-contiguous nature of lists (non-linear linked-lists) § behavior of primitive operations (car, cdr, cons) (car '(a b c)) ≡ (car '(a . (b . (c . ())))) à a (cdr '(a b c)) ≡ (cdr '(a . (b . (c . ())))) à (b . (c . ())) ≡ (b c) (cons 'x '(a b c)) ≡ (cons 'x '(a . (b . (c . ())))) à (x . (a . (b . (c . ())))) ≡ (x a b c) () Structure sharing • since destrucGve assignments are rare, Scheme makes extensive use of structure-­‐ sharing (define (my-length lst) (if (null? lst) 0 (+ 1 (my-length (cdr lst))))) Ø (my-length '(a b c)) 3 a b c – each recursive call shares a part of the list () Garbage collecGon • garbage collecGon is used to reclaim heap memory (define (f1 x y z) (cons x (f2 y z))) (define (f2 v w) (cons v w)) Ø (f1 'a '(b c) '(d e)) (a (b c) d e) 78 Structuring data • an associaGon list is a list of "records" – each record is a list of related informaGon, keyed by the first field • (define NAMES '((Smith Pat Q) • (Jones Chris J) • (Walker Kelly T) • (Thompson Shelly P))) note: can use define to create "global constants" (for convenience) § can access the record (sublist) for a particular entry using assoc Ø (assoc 'Smith NAMES) (Smith Pat Q) Ø (assoc 'Walker NAMES) (Walker Kelly T) § assoc traverses the association list, checks the car of each sublist (define (my-assoc key assoc-list) (cond ((null? assoc-list) #f) ((equal? key (caar assoc-list)) (car assoc-list)) (else (my-assoc key (cdr assoc-list))))) AssociaGon lists • to access structured data, – store in an associaGon list with search key first – access via the search key (using assoc) – use car/cdr to select the desired informaGon from the returned record • (define MENU '((bean-burger 2.99) • (tofu-dog 2.49) • (fries 0.99) • (medium-soda 0.79) • (large-soda 0.99))) Ø (cadr (assoc 'fries MENU)) 0.99 Ø (cadr (assoc 'tofu-dog MENU)) 2.49 (define (price item) (cadr (assoc item MENU))) assoc example • consider a more general problem: determine price for an enGre meal – represent the meal order as a list of items, • e.g., (tofu-dog fries large-dew) – use recursion to traverse the meal list, add up price of each item (define (meal-price meal) (if (null? meal) 0.0 (+ (price (car meal)) (meal-price (cdr meal))))) § alternatively, could use map & apply (define (meal-price meal) (apply + (map price meal))) Non-­‐linear data structures • note: can represent non-­‐linear structures using lists dog • e.g. trees bird • possum aardvark cat frog • wolf (dog (bird (aardvark () ()) (cat () ())) • (possum (frog () ()) (wolf () ()))) § empty tree is represented by the empty list: () § non-empty tree is represented as a list: (ROOT LEFT-SUBTREE RIGHT-SUBTREE) § can access the the tree efficiently (car TREE) (cadr TREE) (caddr TREE) è è è ROOT LEFT-SUBTREE RIGHT-SUBTREE Tree rouGnes • • • • (define TREE1 ' (dog (bird (aardvark () ()) (cat () ())) (possum (frog () ()) (wolf () ())))) • • (define (empty? tree) (null? tree)) dog bird • • • • (define (root tree) (if (empty? tree) 'ERROR (car tree))) • (define (left-subtree tree) (if (empty? tree) 'ERROR (cadr tree))) • • • aardvark tree) possum cat frog wolf (define (right-subtree (if (empty? tree) 'ERROR (caddr tree))) Tree searching note: can access root & either subtree in constant time à can implement binary search trees with O(log N) access binary search tree: for each node, all values in left subtree are <= value at node all values in right subtree are > value at node 27 15 4 33 22 32 (define (bst-contains? bstree sym) (cond ((empty? tree) #f) ((= (root tree) sym) #t) ((> (root tree) sym) (bst-contains? (left-subtree tree) sym)) (else (bst-contains? (right-subtree tree) sym)))) note: recursive nature of trees makes them ideal for recursive traversals 34 Tree traversal • • • • • • (define (pre-order tree) (if (null? tree) '() (append (list (car tree)) (pre-order (cadr tree)) (pre-order (caddr tree))))) • • • • • • (define (in-order tree) (if (null? tree) '() (append (in-order (cadr tree)) (list (car tree)) (in-order (caddr tree))))) • • • • • • (define (post-order tree) (if (null? tree) '() (append (post-order (cadr tree)) (post-order (caddr tree)) (list (car tree))))) dog bird aardvark possum cat frog pre-order traversal? in-order traversal? post-order traversal? wolf Finally, variables! • Scheme does provide for variables and destrucGve assignments Ø (define x 4) #<unspecified> define creates and iniGalizes a variable Ø x 4 Ø (set! x (+ x 1)) #<unspecified> set! updates a variable Ø x 5 since Scheme is statically scoped, can have global variables YUCK: destroys functional model, messes up structure sharing Let expression fortunately, Scheme provides a "clean" mechanism for creating variables to store (immutable) values (let ((VAR1 VALUE1) (VAR2 VALUE2) . . . (VARn VALUEn)) EXPRESSION) let expression introduces a new environment with variables (i.e., a block) good for naming a value (don't need set!) a let expression has the same effect as creating a help function & passing value as long as destructive assignments are not used, the functional model is preserved § in particular, structure sharing is safe (let ((x 5) (y 10)) (let (z (x + y)) ) ) environment where z = 15 environment where x = 5 and y = 10