(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)))))

(define (point.dimension pt) (length pt))

(define (length l)
  (if (null? l)
      0
      (+ 1 (length (cdr l)))))

(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)))))

(define (point.to-origin pt) (distance pt origin-3d))

(define (point.to-origin pt)
  ;; Part of the IMPLEMENTATION of points, so it knows 
  ;; the specific representation! 
  (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)))))

(define (add-up list-of-numbers)
  (if (null? list-of-numbers)
      0
      (+ (car list-of-numbers)
         (add-up (cdr list-of-numbers)))))

(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)))

(define (inside-unit-sphere? point)
  (<= (point.to-origin point) 1))

(define (those-inside-unit-sphere list-of-points)
  (filter inside-unit-sphere? 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)))))

(define (how-many-in-unit-sphere points)
  (accumulate 0 +
              (map (lambda (pt) 1)
                   (filter inside-unit-sphere? points))))

(define (add . numbers)
  (add-up numbers))

(define (list . elements) elements)

(define (point.to-origin pt)
  (sqrt (apply + (map square pt))))

