;; Functional version of insert (no side effects):

(define (insert n olist)
  (cond ((null? olist) (cons n '()))
	((< n (car olist)) (cons n olist))
	((= n (car olist)) olist)
	(else (cons (car olist)
		    (insert n (cdr olist)) )) ))

;; Examples to try:
;;
;; > (define a (list 3 7 20))
;; > (define b (insert 15 a))
;; > b
;; > a
;;
;; > (trace cons)
;; > (insert 1 b)    ; only does one cons
;; > (insert 27 b)   ; has to do 5 conses


;; New version (avoids copying pairs from the original list):

(define (insert! n olist)
  (cond ((null? (cdr olist)) (set-cdr! olist (cons n '())))
	((< n (cadr olist)) (set-cdr! olist (cons n (cdr olist))))
	((= n (cadr olist)) #f)   ; returned value doesn't matter
	(else (insert! n (cdr olist))) ))

;; Examples to try:
;;
;; > (define a (list '*olist* 3 7 20))    ; remember we need a header
;; > (define b (insert! 15 a))
;; > b   ; Note that b doesn't have the answer!
         ; Insert! works by changing a:
;; > a
;;
;; > (trace cons)
;; > (insert! 1 a)    ; only does one cons
;; > (insert! 27 a)   ; so does this one


;; Improved version of insert!, using an ADT:

(define (make-empty-olist)
  (cons '*olist* '())) ;; header is ignored generally

(define (empty-olist? olist)
  (null? (cdr olist)))

(define (first-in-olist olist)
  (cadr olist))

(define (rest-of-olist olist)
  (cdr olist))

(define (add-to-olist! item olist)
  (set-cdr! olist (cons item (cdr olist))))

(define (insert! n olist)
  (cond ((empty-olist? olist) (add-to-olist! n olist))
	((< n (first-in-olist olist)) (add-to-olist! n olist))
	((= n (first-in-olist olist)) #f)   ; returned value doesn't matter
	(else (insert! n (rest-of-olist olist))) ))

;; > (define c (make-empty-olist))
;; > (insert! 5 c)
;; > (insert! 8 c)
;; > ...