;USING FUNCTIONS TO REP DATA
(set point-maker
  (lambda (x y)
    (lambda (msg args)
      (if (= msg 'abscissa)
	  x
      (if (= msg 'ordinate)
	  y
      (if (= msg 'new-x)
	  (point-maker (car args) y)
      (if (= msg 'new-y)
	  (point-maker x (car args)))))))
    ))

(set mp (point-maker 3 4))

(mp 'abscissa '())

(set send
  (lambda (object message args)
    (object message args)))

(set send0
  (lambda (object message)
    (send object message '())))

(send0 mp 'abscissa)

(send mp 'new-x '(7))

	; CONTINUATIONS
(set point2
  (lambda (x y)
    (lambda (f)
      (f x y))))

(set mp2 (point2 3 4))

(set abscissa
  (lambda (p)
    (p (lambda (x y) x))))

(set ordinate
  (lambda (p)
    (p (lambda (x y) y))))

(set new-x
  (lambda (p x2)
    (p (lambda (x y) (point2 x2 y)))))

	; INFINITE DATA
(set null-sequence
  ; TYPE: sequence = nat -> int
  (lambda (n) 0))

(set update-sequence
  ; TYPE: sequence, nat, int -> sequence
  (lambda (seq m x)
     (lambda (n) (if (= n m) x (seq n)))))

(set nth-sequence
  ; TYPE: sequence, nat -> int
  (lambda (seq n)
    (seq n)))

(set evens
  (lambda (n) (if (= (mod n 2) 0) n 0)))

      ; CURRIED FIRST APPROACH
(set nullset '())  ; TYPE: all a. set of a
(set addelt
 ;TYPE: all a. (a,a -> bool) -> a, set of a
 ;        -> set of a
 (lambda (eqfun)
   (lambda (x s)
     (if ((member? eqfun) x s) s
       (cons x s)))))
(set member?
  ;TYPE: all a. (a,a -> bool)
  ;  -> (a, set of a -> bool)
  (lambda (eqfun)
    (lambda (x s)
      (find ((curry eqfun) x) s))))
(set union
  ; TYPE: all a. (a,a -> bool)
  ;   -> (set of a, set of a) -> set of a
  (lambda (eqfun)
    (lambda (s1 s2)
      ((combine id
	      (lambda (x s)
		(addelt x s eqfun))
	      s1)
     s2))))

	; EASIER TO USE THIRD APPROACH
(set mk-set-ops
 ; TYPE: all a. (a,a -> bool)
 ;       -> (symbol -> function)
 (lambda (eqfun)
   (lambda (what)
     (if (= what 'nullset) '()
     (if (= what 'member?)
	 (lambda (x s)
	   (find ((curry eqfun) x) s))
     (if (= what 'addelt)
	 (lambda (x s)
	   (if (find ((curry eqfun) x) s)
	       s
	     (cons x s)))
     (if (= what 'union)
	 (lambda (s1 s2)
	   ((combine id
		     (lambda (x s)
		       (addelt x s eqfun))
		     s1)
	    s2)))))))))

(set al-ops (mk-set-ops =alist))
(set al-nullset (al-ops 'nullset))
(set al-member? (al-ops 'member?))
(set al-addelt (al-ops 'addelt))
(set al-union (al-ops 'union))

; OBJECT-ORIENTED (eqfun part of objects)
(set mkEqObj
  ; TYPE: all a. a, (a,a -> bool)
  ;        -> EqObj of a
  (lambda (self eqfun)
    (lambda (msg)
      (if (= msg 'eq)
          (lambda (x)
            ; TYPE: a -> bool
	    (eqfun self x))
      (if (= msg 'value)
	  self
	(error-not-understood))))
    ))
(set send0 (obj msg)
  (obj msg))
(set send1 (obj msg arg)
  ((obj msg) arg))
(set send2 (obj msg arg1 arg2)
  ((obj msg) arg1 arg2))

(set mkSet (lambda ()
 ((lambda (initSet)
    (initSet '()))
  (lambda (self)
    ; TYPE: all a. list of EqObj of a
    ;            -> Set of a
    (lambda (msg)
      (if (= msg 'addelt)
	  (lambda (x)
            ; TYPE: EqObj of a -> Set of a
	    (if (send1 self 'member?
		      (send0 x 'value))
	       self
	     (mkSet (cons x self))))
      (if (= msg 'member?)
	  (lambda (x)
	    ; TYPE: a -> bool
	    (find (lambda (y) (send1 e 'eq x))
		  self))
      (if (= msg 'union)
	  (lambda (s2)
	    ; TYPE: Set of a -> Set of a
	    ((combine id
		      (lambda (x s)
			(send1 s addelt x))
		      self)
	     s2))
	(error-not-understood)))))
    ))))
