PPL Pairs, lists and data abstraction. Compound Data Until now: atomic, unrelated entities Now: organized into structures Why? – Better conceptual level.

Slides:



Advertisements
Similar presentations
Lisp. Versions of LISP Lisp is an old language with many variants Lisp is alive and well today Most modern versions are based on Common Lisp LispWorks.
Advertisements

Semantics Static semantics Dynamic semantics attribute grammars
Lists in Lisp and Scheme a. Lists are Lisp’s fundamental data structures, but there are others – Arrays, characters, strings, etc. – Common Lisp has moved.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Getting started with ML ML is a functional programming language. ML is statically typed: The types of literals, values, expressions and functions in a.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
מבוא מורחב 1 Lecture #7. מבוא מורחב 2 The rational number abstraction Wishful thinking: (make-rat ) Creates a rational number (numer ) Returns the numerator.
Evaluators for Functional Programming Chapter 4 1 Chapter 4 - Evaluators for Functional Programming.
(define applicative-eval (lambda (exp) (cond ((atomic? exp) (eval-atomic exp)) ((special-form? exp) (eval-special-form exp)) ((list-form? exp) (eval-list.
Lisp. Versions of LISP Lisp is an old language with many variants –LISP is an acronym for List Processing language Lisp is alive and well today Most modern.
Functional programming: LISP Originally developed for symbolic computing Main motivation: include recursion (see McCarthy biographical excerpt on web site).
Data Abstraction… The truth comes out…. What we’re doing today… Abstraction ADT: Dotted Pair ADT: List Box and Pointer List Recursion Deep List Recursion.
מבוא מורחב - שיעור 81 Lecture 8 Lists and list operations (continue).
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
SchemeCOP Introduction to Scheme. SchemeCOP Scheme Meta-language for coding interpreters –“ clean ” semantics Scheme = LISP + ALGOL –simple.
PPL Syntax & Formal Semantics Lecture Notes: Chapter 2.
PPL Syntax & Formal Semantics Lecture Notes: Chapter 2.
PPL Pairs, lists and data abstraction. Data Abstraction? An interface: separate implementation from usage Think of the Map interface in Java: we know.
Spring 2008Programming Development Techniques 1 Topic 6 Hierarchical Data and the Closure Property Section September 2008.
1 Lisp Functions –Built-in functions –Defining functions –Function Evaluation and Special Forms defun, if Control statements –Conditional if, cond –Repetition.
Introduction to Scheme CS 480/680 – Comparative Languages “And now for something completely different…” – Monty Python “And now for something completely.
Practice session #6: 1. Sequence operations 2. Partial evaluation with currying 3. Lazy-lists.
1 Subt. model interpreter: Structure of the interpreter ASP Derived expressions Core Test Data structures Utils A racket lib Proc / Primitive-Proc. Global.
COP4020 Programming Languages Functional Programming Prof. Xin Yuan.
1 You’re Invited! Course VI Freshman Open House! Friday, April 7, :30-5:00 PM FREE Course VI T-Shirts (while supplies last) and Department.
18-October-2002cse Symbols © 2002 University of Washington1 Symbols CSE 413, Autumn 2002 Programming Languages
מבוא מורחב 1 Lecture #9. מבוא מורחב 2 Symbol: a primitive type constructors: (quote alpha) ==> quote is a special form. One argument: a name. selectors.
LISP Data Types Functional Programming Academic Year Alessandro Cimatti
1 Subt. model interpreter: Introduction Abstract Syntax Parser Abstract Syntax Parser Derived Expressions Core Test Data Structures Utils (a racket lib)
1 Data Abstraction. Pairs and Lists. (SICP Sections – 2.2.1)
PPL CPS. Moed A 2007 Solution (define scale-tree (λ (tree factor) (map (λ (sub-tree) (if (list? sub-tree) (scale-tree sub-tree factor) (* sub-tree.
PPL CPS. Moed A 2007 Solution (define scale-tree (λ (tree factor) (map (λ (sub-tree) (if (list? sub-tree) (scale-tree sub-tree factor) (* sub-tree.
מבוא מורחב שיעור 7 1 Lecture 7 Data Abstraction. Pairs and Lists. (Sections – 2.2.1)
PPL Syntax & Formal Semantics Lecture Notes: Chapter 2.
CS 152: Programming Language Paradigms February 12 Class Meeting Department of Computer Science San Jose State University Spring 2014 Instructor: Ron Mak.
Principles Of Programming Languages Lecture 2 Today Design-By-Contract Data Structures: Lists and Pairs Iteration vs. Recursion If we have time: live.
PPL Leftovers: LET Syntax & Formal Semantics Static Verification: Type Inference Lecture Notes: Chapter 2.
Edited by Original material by Eric Grimson
Representing Sets (2.3.3) Huffman Encoding Trees (2.3.4)
Pairs and Lists. Data Abstraction. SICP: Sections – 2.2.1
PPL Lecture Notes: Chapter 3 High-Order Procedures Revisited.
Introduction to Scheme
September 4, 1997 Programming Languages (CS 550) Lecture 6 Summary Operational Semantics of Scheme using Substitution Jeremy R. Johnson TexPoint fonts.
Lecture 14 - Environment Model (cont.) - Mutation - Stacks and Queues
Lists in Lisp and Scheme
Env. Model Implementation
Type checking and inference
6.001 SICP Data abstractions
The Metacircular Evaluator
PPL Sequence Interface.
The Metacircular Evaluator
Chapter 4 Data and Behavior Abstraction
The Metacircular Evaluator (Continued)
6.001 SICP Further Variations on a Scheme
Lecture #9 מבוא מורחב.
Data Mutation Primitive and compound data mutators set! for names
Lecture 14 - Environment Model (cont.) - Mutation - Stacks and Queues
6.001 SICP Variations on a Scheme
Mutators for compound data Stack Queue
6.001 SICP Data Mutation Primitive and Compound Data Mutators
Lecture 14: The environment model (cont
Announcements Quiz 5 HW6 due October 23
Lecture #7 מבוא מורחב.
List and list operations (continue).
Today’s topics Abstractions Procedural Data
Functional Programming: Lisp
6.001 SICP Interpretation Parts of an interpreter
Lecture # , , , , מבוא מורחב.
Lisp.
More Scheme CS 331.
Presentation transcript:

PPL Pairs, lists and data abstraction

Compound Data Until now: atomic, unrelated entities Now: organized into structures Why? – Better conceptual level of design – Modularity – Maintenance – Code reuse Actually a new type in the signature

Data Abstractions in Scheme? Of course, but first we need to present 2 new data types in Scheme: – Pairs – Lists

Pairs Combines two data entities into a single unit Scheme provides built in primitives: – Value constructor: cons – Selectors: car, cdr – Identify predicate: pair? – Equality: equal?

Pairs > (define x (cons 1 2)) > (car x) 1 > (cdr x) 2 > x (1. 2) “toString” of pair

Pairs Each data entity can be anything! > (define y (cons x (quote a))) > (car y) (1. 2) > (cdr y) 'a > y ((1. 2). a) Recall that x is the pair (cons 1 2)

Pairs Do not confuse (cons 1 2) with (1. 2) !! 1 st is a Scheme expression (syntax) and 2 nd is the ‘toString’ of the value (same as lambda and procedure)

Pair Type Type constructor: Pair Type of: cons : [T 1 *T 2 -> Pair(T 1,T 2 )] car : [Pair(T 1,T 2 ) -> T 1 ] cdr : [Pair(T 1,T 2 ) -> T 2 ]

Church Numbers Defined recursively: – Zero is a Church number. – For a Church number c, S(c) is a Church number Symbolic representation of natural numbers: – Zero, S(Zero), S(S(Zero)),… So what does it have to do with us? – We can represent them using pairs! – Zero, (S.Zero), (S.(S.Zero)), …

Church Numbers using Recursive Pairs ;; Type: [Number -> Church-num] (define church-num (λ (n) (if (zero? n) 'Zero (cons 'S (church-num (- n 1)))))) > (church-num 3) '(S S S. Zero) ;(cons ‘S (cons ‘S (cons ‘S ‘Zero))))

Church Numbers using Recursive Pairs ;; Type: Church-num -> Number (define church-val (λ (c-n) (if (eq? c-n 'Zero) 0 (+ 1 (church-val (cdr c-n))))))

Useful Example (define member (lambda (el pair) (cond ((and (member-type-test el (car pair)) (member el (car pair))) #t) ((eq? el (car pair)) #t) ((and (member-type-test el (cdr pair)) (member el (cdr pair))) #t) ((eq? el (cdr pair)) #t) (else #f)))) (define member-type-test (lambda (el pair-candidate) (and (symbol? el) (pair? pair-candidate))))

Lists Finite sequence  (v 1 … v n ) v 1 is head, (v 2 … v n ) is tail Value constructors: cons and list – Empty: (list) – Non-empty: (cons head tail) – tail must be a list! (list e 1 … e n )

List Implementation Lists are actually nested pairs! The inmost item is an empty list Printing form of list is nice: – ( … )

Lists Both will create the same list: (list 1 2 3) (cons 1 (cons 2 (cons 3 (list))))

Lists Selectors: – car : head – cdr : tail Predicates: – list? – null? – equal?

Examples > (define one-through-four (list )) > one-through-four ( ) > (car one-through-four) 1 > (cdr one-through-four) (2 3 4) > (car (cdr one-through-four)) 2

Note on Pairs and Lists Pair and List types have same value constructor and selector Scheme can live with it because its dynamically typed

Visual Representation Empty list Non empty list ((1 2) 3 4) : 3124

Lists and Types Homogenous – Examples: (1 2 3), ((1 2) (3)) – LIST(Number), LIST(T), … Heterogeneous – Examples: (1 #f 3), ((1 2) 3) – LIST

Useful List Operations car + cdr: > (define x (list )) > (car x) 5 > (cdr x) (6 8 2) > (car (cdr x)) 6 > (cadr x) 6 > (cddr x) (8 2)

Selector: list-ref n th element of a list: ;; Type: [LIST * Number -> T] (define list-ref (λ (l n) (if (= n 0) (car l) (list-ref (cdr l) (- n 1))))) (define squares (list )) (list-ref squares 4)

Operator: length (define length (λ (l) (if (null? l) 0 (+ 1 (length (cdr l)))))) (define squares (list )) (length squares) 6

Iterative length (define length (λ (l) (letrec ((iter (λ (l c) (if (null? l) c (iter (cdr l) (+ c 1)))))) (iter l 0))))

Operator: append (define append (λ (l1 l2) (if (null? l1) l2 (cons (car l1) (append (cdr l1) l2))))) (append (list 1 2 3) (list 3 4))

Iterative append ;; Type: [LIST * LIST -> LIST] (define append (λ (l1 l2) (letrec ((iter (λ (l1 l2 c) (if (null? l1) (c l2) (iter (cdr l1) l2 (λ (app-cdr-l1) (c (cons (car l1) app-cdr-l1)))))))) (iter l1 l2 (lambda (x) x)))))

Constructor make-list Builds a list of given with given values (define make-list (λ (l v) (if (= l 0) (list) (cons v (make-list (- l 1) v)))))

Using Lists to Represent Trees Unlabeled trees: – Empty tree () – Leaf is just value – Non-empty tree – non-empty list Example: (1 (2 3)) is the tree:

Using Lists to Represent Trees How can we add data to non-leaf nodes? (i.e. labeled tree) : each node is also a list! ((1) ((2) (3))) Now we can create labeled trees: (1 (0) (3 (2) (4)))

Leaves Count Unlabeled tree (define count-leaves (λ (t) (cond ((null? t) 0) ((not (list? t)) 1) (else (+ (count-leaves (car t)) (count-leaves (cdr t)))))))

Type Correctness with Pairs and Lists cons and list are primitives (not special forms!) So we need more axioms.

Pairs For every type environment _Tenv and type expressions _S,_S 1,_S 2 : Tenv |- cons:[S 1 *S 2 -> PAIR(S 1,S 2 )] Tenv |- car:[PAIR(S 1,S 2 ) -> S 1 ] Tenv |- cdr:[PAIR(S 1,S 2 ) -> S 2 ] Tenv |- pair?:[S -> Boolean] Tenv |- equal?:[PAIR(S 1,S 2 )*PAIR(S 3,S 4 ) -> Boolean]

Homogenous Lists For every type environment Tenv and type expression S: Tenv |- list:[Empty -> LIST(S)] Tenv |- list:[S*...*S -> LIST(S)] n >0 Tenv |- cons:[S*LIST(S) -> LIST(S)] Tenv |- car:[LIST(S) -> S] Tenv |- cdr:[LIST(S) -> LIST(S)] Tenv |- null?:[LIST(S) -> Boolean] Tenv |- list?:[S -> Boolean] Tenv |- equal?:[LIST(S)*LIST(S) -> Boolean]

Heterogeneous Lists For every type environment Tenv and type expression S: Tenv |- list:[Empty -> LIST] Tenv |- cons:[S*LIST -> LIST] Tenv |- car:[LIST -> S] Tenv |- cdr:[LIST -> LIST] Tenv |- null?:[LIST -> Boolean] Tenv |- list?:[S -> Boolean] Tenv |- equal?:[LIST*LIST -> Boolean]

Type Derivation Example (define first-first (λ (p) (car (car p)))) 1. {p:T 1 } |- p: T 1 2. { } |- car : [Pair(T 2,T 3 ) -> T 2 3. {p: Pair(T 2,T 3 )} |- (car p):T 2 4. { } |- car : [Pair(T 21,T 31 ) -> T {p: Pair(T 22,T 32 )} |- (car p):T {p: Pair(Pair(T 21,T 31 ),T 32 )} |- (car (car p)): T {} |- (λ (p)…): [Pair(Pair(T 21,T 31 ),T 32 ) -> T 21 ] 9. { } |- first- first : [Pair(Pair(T 21,T 31 ),T 32 ) -> T 21 ]

What About Data Abstraction (ADT)? An interface: separation between usage (client) and implementation (supplier) Supplier gives constructors and selectors (getters), and client uses them. Order of development: 1.Client level 2.Supplier level

ADT It’s a new type with a difference: type is semantic while ADT is syntactic Signature of constructor Signature of operators Rules of correctness (Invariants)

So Why Start with Pairs and Lists? Pairs and lists will be our implementation! The client will not know we used pairs and lists, she will just use the operations we give her! Example next slide

Binary Tree ADT: Constructors Signature: make-binary-tree(l,r) Purpose: Returns a binary tree whose left sub- tree is l and whose right sub-tree is r Type: [Binary-Tree*Binary-Tree -> Binary-Tree] Pre-condition: binary-tree?(l) and binary- tree?(r) Signature: make-leaf(d) Purpose: Returns a leaf binary-tree whose data element is d Type: [T -> Binary-Tree]

Binary Tree ADT: Selectors Signature: left-tree(r), right-tree(r) Purpose: (left-tree ): Returns the left sub- tree of the binary-tree. (right-tree ): Returns the right sub-tree of the binary-tree. Type: [Binary-Tree -> Binary-Tree] Pre-condition: composite-binary-tree?(t) Signature: leaf-data(r) Purpose: Returns the data element of the leaf binary-tree. Type: [Binary-Tree -> T] Pre-condition: leaf?(t)

Binary Tree ADT: Predicates Signature: leaf?(t) Type: [T -> Boolean] Post-condition: true if t is a leaf -- constructed by make-leaf Signature: composite-binary-tree?(t) Type: [T -> Boolean] Post-condition: true if t is a composite binary-tree -- constructed by make-binary-tree Signature: binary-tree?(t) Type: [T -> Boolean] Post-condition: result = (leaf?(t) or composite-binary-tree?(t) ) Signature: equal-binary-tree?(t1, t2) Type: [Binary-Tree*Binary-Tree -> Boolean]

Binary Tree ADT: Invariants leaf-data(make-leaf(d)) = d left-tree(make-binary-tree(l,r)) = l right-tree(make-binary-tree(l,r)) = r leaf?(make-leaf(d)) = true leaf?(make-binary-tree(l,r)) = false composite-binary-tree?(make-binary- tree(l,r)) = true composite-binary-tree?(make-leaf(d)) = false

Binary Tree ADT: Client Level ;Signature: count-leaves(tree) ;Purpose: Count the number of leaves of ’tree’ ;Type: [binary-Tree -> number] (define count-leaves (lambda (tree) (if (composite-binary-tree? tree) (+ (count-leaves (left-tree tree)) (count-leaves (right-tree tree))) 1)))

Binary Tree ADT: Client Level More examples in lecture notes. Look at them. Really, look at them.

Binary Tree ADT: Implementation (supplier) ;Signature: make-binary- tree(l,r) ;Type: [T 1 *T 2 -> LIST] ;Pre-condition: binary-tree?(l) ; and binary-tree?(r) (define make-binary-tree (lambda (l r) (list l r))) ;Signature: make-leaf(d) ;Type: [T -> T] (define make-leaf (lambda (d) d)) ;Signature: left-tree(t) ;Type: [LIST -> T] ;Pre-condition: composite- binary-tree?(t) (define left-tree (lambda (t) (car t))) ;Signature: right-tree(t) ;Type: [LIST -> T] ;Pre-condition: composite- binary-tree?(t) (define right-tree (lambda (t) (cadr t)))

Binary Tree ADT: Implementation ;Signarture: leaf-data(t) ;Type: [T -> T] ;Pre-condition: leaf?(t) (define leaf-data (lambda (t) t)) ;Signarture: leaf?(t) ;Type: [T -> Boolean] (define leaf? (lambda (t) #t)) ;Signarture: composite-binary-tree?(t) ;Type: [T -> Boolean] (define composite-binary-tree? (lambda (t) (and (list? t) (list? (cdr t)) (null? (cddr t)) (binary-tree? (left-tree t)) (binary-tree? (right-tree t)))

Binary Tree ADT: Implementation ;Signarture: binary- tree(t) ;Type: [T -> Boolean] (define binary-tree? (lambda (t) (or (leaf t) (composite-b-t t)))) ;Signature: equal-binary-tree?(t1,t2) ;Type: [T1*T2 -> Boolean] ;Pre-condition: binary-tree?(t1) and binary-tree?(t2) (define equal-binary-tree? (λ (t1 t2) (cond ((and (composite-binary-tree? t1) (composite-binary-tree? t2)) (and (equal-binary-tree? (left-tree t1) (left-tree t2)) (equal-binary-tree? (right-tree t1) (right-tree t2)))) ((and (leaf? t1) (leaf? t2)) (equal? (leaf-data t1) (leaf-data t2))) (else #f))))

Binary Tree ADT: Invariants Seems ok, but look: > (leaf? (make-leaf (list 5 6))) #t > (has-leaf? (list 5 6) (make-leaf (list 5 6))) #f We have no way to distinct composite leaves from tree… We need a better implementation: tagged-data!

Tagged Data ADT Signature: attach-tag(x,tag) Purpose: Construct a tagged- data value Type: [T*Symbol -> Tagged- data(T)] Signature: get-tag(tagged) Purpose: Select the tag from a tagged-data value Type: [Tagged-data(T) -> Symbol] Signature: get-content(tagged) Purpose: Select the data from a tagged-data value Type: [Tagged-data(T) -> T] Signature: tagged-data?(datum) Purpose: Identify tagged-data values Type: [T -> Boolean] Signature: tagged-by? (tagged,tag) Purpose: Identify tagged-data values Type: [T*Symbol -> Boolean]

Binary Tree ADT: Implementation using Tagged-Data ;Signature: make-binary-tree(l,r) ;Type: [(LIST union T1)*(LIST union T2) ; -> Tagged-data(LIST)] ;Pre-condition: binary-tree?(l) ; and binary-tree?(r) (define make-binary-tree (lambda (l r) (attach-tag (list l r) ’composite-binary-tree))) ;Signature: make-leaf(d) ;Type: [T -> Tagged-data(T)] (define make-leaf (lambda (d) (attach-tag d ’leaf))) ;Signature: left-tree(t) ;Type: [Tagged-data(LIST) ; -> Tagged-data(LIST union T)] ;Pre-condition: composite-binary- tree?(t) (define left-tree (lambda (t) (car (get-content t)))) ;Signature: right-tree(t) ;Type: [Tagged-data(LIST) -> Tagged-data(LIST union T)] ;Pre-condition: composite-binary- tree?(t) (define right-tree (lambda (t) (cadr (get-content t))))

Proving Invariants Invariant: leaf-data(make-leaf (d)) = d : For expression d, eval[(leaf-data (make-leaf d))] = eval[d] eval[(leaf-data (make-leaf d))] ==> eval[(leaf-data (attach-tag eval[d] ’leaf))] ==> eval[(get-content (attach-tag eval[d] ’leaf))] ==> eval[d]

Tagged-Data Implementation Have you noticed that we didn’t implement the tagged-data ADT? That’s the whole idea! We are clients! We don’t have to know the implementation! But we’ll give it anyway…

Tagged-Data ADT Implementation ;Signature: attach-tag(x,tag) ;Type: [Symbol*T -> PAIR(Symbol, T)] (define attach-tag (λ (x tag) (cons tag x))) ;Signature: get-tag(tagged) ;Type: PAIR(Symbol,T) -> Symbol (define get-tag (λ (tagged) (car tagged))) ;Signature: get-content(tagged) ;Type: [PAIR(Symbol,T) -> T] (define get-content (λ (tagged) (cdr tagged))) ;Signature: tagged-data?(datum) ;Type: [T -> Boolean] (define tagged-data? (λ (datum) (and (pair? datum) (symbol? (car datum))))) ;Signature: tagged-by?(tagged,tag) ;Type: [T*Symbol -> Boolean] (define tagged-by? (λ (tagged tag) (and (tagged-data? tagged) (eq? (get-tag tagged) tag))))

Type Inference with Type Constraints using ADT ADT: – Type expression (TE) – Substitution – Equation Client produces – sub-application, sub-combination – Infer-type, solve Implementation – TE is tagged-data (tag is type constructor) – Substitution is 2-element list – Equation is 2-element list

Type Inference with Type Constraints using ADT Full implementation in course site. We describe part of it.

Type Expression ADT (partial) Constructors: Signature: make-proc-te(tuple-te, te) Type: Client view: [Tuple*Type -> Procedure] Example: (make-proc-te (make-tuple-te (list Number)) 'Number) ==> (-> (*Number) Number) Signature: make-tuple-te(te-list) Type: Client view:[LIST(TE)-> Tuple] Example: (make-tuple-te (list 'Number (make-proc-te (make-tuple-te (list 'Number))'T1))) ==> (* Number (-> (* Number) T1)) Some getters: Signature: get-constructor(te) Type: Client view: [Composite-Type-Expression -> Symbol] Example: (get-constructor (make-tuple-te (list 'Number 'Number))) ==> * Signature: tuple-components(te) Type: Client view: [Tuple -> List(TE)] Example: (tuple-components (make-tuple-te (list 'Number 'Number))) ==> (Number Number) Signature: proc-return-te(te) Type: Client view:[Procedure -> TE] Example: (proc-return-te (make-proc-te (make- tuple-te (list 'Number)) 'T1)) ==> T1 Some predicates: Signature: equal-atomic-te?(te1 te2) Type: [LIST union Symbol * LIST union Symbol -> Boolean] Signature: type-expr?(te) Type: [T -> Boolean]

Procedures as Data So far we’ve seen only pairs and lists as compound data Procedures can be data too! And in more than one way What?! Procedures can be data?! Yes.

Pair ADT Suppose Scheme did not include the built-in Pair or List type Pair ADT – Define the ADT (cons’r, getters, etc) – Implement it using procedures(!!)

Pair ADT: Cons’r, Getters, Predicates… Signature: cons(x,y) Type: [T1*T2 -> PAIR(T1,T2)] Signature: car(p) Type: [PAIR(T1,T2) -> T1] Signature: cdr(p) Type: [PAIR(T1,T2) -> T2] Signature: pair?(p) Type: [T -> Boolean] Signature: equal-pair?(p1,p2) Type: [PAIR(T1,T2)*PAIR(T1,T2) -> Boolean]

Pair ADT: Invariants (car (cons x y)) = x (cdr (cons x y)) = y

Pair ADT Implementation I: Eager (also called message passing) ;Signature: cons(x,y) ;Type: [T1*T2 -> [Symbol -> (T1 union T2)] (define cons (λ (x y) (λ (m) (cond ((eq? m 'car) x) ((eq? m 'cdr) y) (else (error "..." m) ))))) Not to confuse with applicative-eval!

Pair ADT Implementation I: Eager ;Signature: car(pair) ;Type: [[Symbol -> (T1 union T2)] -> T1] (define car (λ (pair) (pair ’car))) ;Signature: cdr(pair) ;Type: [[Symbol -> (T1 union T2)] -> T2] (define cdr (λ (pair) (pair ’cdr)))

What Just Happened? A pair is a procedure that stores the information about the pair components The “magic”: – The substitution: the values are “planted” in the procedure – The returned value is a procedure that is not applied. car and cdr apply it.

applicative-eval[ (cons 1 2) ] ==>* <closure (m) (cond ((eq? m ’car) 1) ((eq? m ’cdr) 2) (else (error “…" m) ))>

applicative-eval[ (car (cons 1 2 )) ] ==> applicative-eval[ car ] ==> applicative-eval[ (cons 1 2) ] ==>* sub[pair,, (pair ’car) ] ==> ( ’car) reduce: ( (lambda (m) (cond ((eq? m ’car) 1) ((eq? m ’cdr) 2) (else (error "Argument not ’car or ’cdr -- CONS" m) ))) ’car) ==>* applicative-eval, sub, reduce: (cond ((eq? ’car ’car) 1) ((eq? ’car ’cdr) 2) (else (error “…" ’car) )) ==> 1

Pair ADT Implementation II: Lazy Lazy ;Signature: cons(x,y) ;Type: [T1*T2 ; -> [ [T1*T2 -> T3] -> T3]] (define cons (lambda (x y) (lambda (sel) (sel x y)))) Eager ;Signature: cons(x,y) ;Type: [T1*T2 -> [Symbol -> (T1 union T2)] (define cons (λ (x y) (λ (m) (cond ((eq? m 'car) x) ((eq? m 'cdr) y) (else (error "..." m))))))

Pair ADT Implementation II: Lazy ;Signature: cons(x,y) ;Type: [T1*T2 -> [ [T1*T2 ; -> T3] -> T3]] (define cons (lambda (x y) (lambda (sel) (sel x y)))) ;Signature: car(pair) ;Type: [[ [T1*T2 -> T3] -> T3] -> T1] (define car (lambda (pair) (pair (lambda (x y) x)))) ;Signature: cdr(pair) ;Type: [[ [T1*T2 -> T3] ; -> T3] -> T2] (define cdr (lambda (pair) (pair (lambda (x y) y))))

applicative-eval[ (cons 1 2) ] ==> applicative-eval[ (car (cons 1 2 )) ] ==>* applicative-eval[ car ] ==> applicative-eval[ (cons 1 2) ] ==>* sub, reduce: applicative-eval[ ( (lambda(x y) x) ) ] ==>* applicative-eval[ ( (lambda(x y) x) 1 2) ] ==> applicative-eval, sub, reduce: 1

Eager vs Lazy Eager More work at constructions time. Immediate at selection time. Selectors that are not simple getters can have any arity. Lazy Immediate at construction time. More work at selection time. Selectors can be added freely, but must have the same arity.