(define origin-3d (list 0 0 0)) (define origin-3d (cons 0 (cons 0 (cons 0 '()))))
(define (list? l) (or (null? l) (and (pair? l) (list? (cdr l)))))
We'd like to know how many dimensions a point has:
(define (point.dimension pt) (length pt)) (define (length l) (if (null? l) 0 (+ 1 (length (cdr l)))))
We'd like the coordinate on a particular axis:
(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 (list-ref l n) (cond ((null? l) (error "...")) ((= 0 n) (car l)) (else (list-ref (cdr l) (- n 1)))))
We'd like to find distance from origin:
(define (point.to-origin pt) (sqrt (add-up (map square pt)))) (define (map fn list-of-values) ; Returns list of same length as list-of-values (if (null? list-of-values) '() (cons (fn (car list-of-values)) (map fn (cdr list-of-values)))))Our first attempt to write add-up:
(define (add-up list-of-numbers) (if (null? list-of-numbers) 0 (+ (car list-of-numbers) (add-up (cdr list-of-numbers)))))Or we can use a common higher-order abstraction:
(define (accumulate initial-value operation list-of-elements) (if (null? list-of-elements) initial-value (operation (car list-of-elements) (accumulate initial-value operation (cdr list-of-elements))))) (define add-up (lambda (l) (accumulate 0 + l)))We'd like to filter out those that are more than 1 unit from the origin:
(define (inside-unit-sphere? point) (<= (point.to-origin point) 1)) (define (those-inside-unit-sphere list-of-points) (filter (lambda (pt) (<= (point.to-origin pt) 1)) list-of-points)) (define (filter test list) (cond ((null? list) '()) ((test (car list)) (cons (car list) (filter test (cdr list)))) (else (filter test (cdr list)))))Now we can do things like:
(define (how-many-in-unit-sphere points) (accumulate 0 + (map (lambda (pt) 1) (filter inside-unit-sphere? points))))
Once we've decided that lists "are the right thing" we can go beyond just writing procedures and "making them primitive for efficiency" like length, list-ref, map, and others (list-copy, reverse, append, sublist, list-head, list-tail).
We can actually change the language so that lists have a special status.
(define (add . numbers) (add-up numbers)) (define (list . elements) elements) (define list (lambda elements elements))
(define (point.to-origin pt) (sqrt (apply + (map square pt))))
(define (tree.farthest node-or-leaf) (if (is-node? node-or-leaf) (tree.farthest (node.outside node-or-leaf)) node-or-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))))
(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 (< (distance smaller) my-distance) (>= (distance not-smaller) my-distance) (tree.valid? smaller) (tree.valid? not-smaller))) #T))The following, more complicated program, does work correctly.
Extra credit question: Can you draw a tree, t, for which (tree.valid? t) returns #T but for which (valid? t) returns #F?
(define (valid? node-or-leaf) (define (min previous new) (if (and previous (<= previous new)) previous new)) (define (max previous new) (if (and previous (>= prevous new)) previous new)) (define (walk node-or-leaf min-OK max-OK) (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 (or (not min-OK) (>= (distance smaller) min-OK)) (or (not max-OK) (<= (distance not-smaller) max-OK)) (walk smaller (min min-OK my-distance) max-OK) (walk not-smaller min-OK (max max-OK my-distance)))) #T)) (walk node-or-leaf #F #F))