MASSACHVSETTS INSTITVTE OF TECHNOLOGY
February 25, 1997
Lecture Notes
Reminder: Quiz One is on Wednesday, March 19, 5pm xor 7pm, Walker 3rd floor Gym.
For our purposes, we can say that a data type is defined by the operations that can be applied to objects of the given type. In Scheme, all of the built-in types (booleans, strings, numbers, procedures, pairs, and others introduced later in the course) are first-class. That is, all objects in Scheme can be...
When we create our own data type, we provide operations that are intended to work only on objects of the type we are creating. Often, we can classify these procedures into the following categories:
Today's example falls in two parts: the n-dimensional point data type from the last lecture (implemented in terms of Scheme lists), and the implementation of lists in terms of pairs.
; The "n-dimensional point" data type, implemented as lists of numbers (define make-point list) (define (point.dimension pt) (length pt)) (define (point.coord pt dim) (list-ref pt (- dim 1))) (define (point.x pt) (point.coord pt 1)) (define (point.y pt) (point.coord pt 2)) (define (point.z pt) (point.coord pt 3)) (define (point.to-origin pt) ;; Distance to origin (sqrt (add-up (map square pt)))) (define add-up (lambda (l) (accumulate 0 + l))) (define (inside-unit-sphere? point) ;; Inside or on surface of unit sphere (<= (point.to-origin point) 1))For much of the lecture we will deal with a standardized use of pairs: lists (in other languages these are called "singly linked lists"). There are many common procedures for manipulating this data structure. Some of them are already built into Scheme or MIT's implementation of Scheme. Here are a few that are used to implement our n-dimensional points:
; Lists implemented using pairs (define (list? l) ;; LIST?: (any) -> Boolean (or (null? l) (and (pair? l) (list? (cdr l))))) (define (length l) ;; LENGTH: (X*) -> Non-negative integer (if (null? l) 0 (+ 1 (length (cdr l))))) (define (list-ref l n) ;; LIST-REF: (X*, Integer) -> X (cond ((null? l) (error "...")) ((= 0 n) (car l)) (else (list-ref (cdr l) (- n 1))))) (define (map fn list-of-values) ;; Returns list of same length as list-of-values ;; ;; MAP: (X->Y, X*) -> Y* (if (null? list-of-values) '() (cons (fn (car list-of-values)) (map fn (cdr list-of-values))))) (define (accumulate initial-value operation list-of-elements) ;; Returns a single value, built by using the OPERATION to combine ;; values from the LIST-OF-ELEMENTS. ;; ;; ACCUMULATE: (X, (Y, X)->X, Y*) -> X (if (null? list-of-elements) initial-value (operation (car list-of-elements) (accumulate initial-value operation (cdr list-of-elements))))) (define (filter test list) ;; Returns a subset of the elements of LIST, consisting of those ;; that satisfy the TEST, in the order they appear in the LIST. ;; ;; FILTER: (X->Boolean, X*) -> X* (cond ((null? list) '()) ((test (car list)) (cons (car list) (filter test (cdr list)))) (else (filter test (cdr list)))))
(define list (lambda elements elements)) ; LAMBDA notation (define (make-point . coords) coords) ; DEFINE notationAnd there is a primitive procedure built in to Scheme, apply, that does the reverse: you give it a procedure and a list of arguments and it calls the procedure with those arguments:
(define x (list 1 2 3 4)) (apply + x) ==> 10 (apply * (list 10 9 8)) ==> 720 (define (point.to-origin pt) ;; Remember: pt is a list of numbers (sqrt (apply + (map square pt))))
; A data abstraction for leaves of a tree: must be points in this ; case (define leaf-tag "Leaf") (define (make-leaf . coords) (cons leaf-tag coords)) (define (is-leaf? obj) (and (pair? obj) (eq? (car obj) leaf-tag))) (define (leaf.point leaf) (cdr leaf)) ; A data abstraction for non-leaf nodes (define node-tag "Node") (define (make-node dist outside on-or-inside) ;; MAKE-NODE: ;; (Sch-Num, (Node + Leaf), (Node + Leaf)) -> Node (list node-tag dist outside on-or-inside)) (define (is-node? obj) (and (pair? obj) (eq? (car obj) node-tag))) (define (node.distance node) (list-ref node 1)) (define (node.outside node) (list-ref node 2)) (define (node.on-or-in node) (list-ref node 3)) ; An operation that works on any kind of node: leaf or non-leaf (define (distance node-or-leaf) (if (is-node? node-or-leaf) (node.distance node-or-leaf) (point.to-origin (leaf.point node-or-leaf)))) ; Some operations on the tree itself (define (tree.farthest node-or-leaf) (if (is-node? node-or-leaf) (tree.farthest (node.outside node-or-leaf)) (leaf.point node-or-leaf))) (define (tree.nearest node-or-leaf) (if (is-node? node-or-leaf) (tree.nearest (node.on-or-in node-or-leaf)) (leaf.point node-or-leaf))) (define (tree.valid? node-or-leaf) (if (is-node? node-or-leaf) (let ((smaller (node.on-or-in node-or-leaf)) (not-smaller (node.outside node-or-leaf)) (my-distance (node.distance node-or-leaf))) (and (tree.valid? smaller) (tree.valid? not-smaller) (< (distance smaller) my-distance) (>= (distance not-smaller) my-distance))) #T))