;

;; First, a few lines to make this file usable as a teachpack
;;    (For details, see htus.org ("how to use scheme"), or
;;     http://www.owlnet.rice.edu/~comp210/02fall/Handouts/teachpack-demo.shtml ) 
;;
(module set (lib "plt-pretty-big.ss" "lang")
  (provide element-of?   ; any, Set --> boolean
           intersect     ; Set, Set --> Set
           union         ; Set, Set --> Set

           cars          ; Set                    (test case)
           reals<10      ; Set                    (test case)
           reals>=4      ; Set                    (test case)    
           )




;; We base our data-def'n of a set on the ways
;; mathematicians write sets.
;; We call it "inft-Set" since it can represent infinite sets.
;      

;; A inft-Set of alpha is either:
;; - a list of alpha, or
;; - alpha --> boolean  (the set's "indicator" function)


; Some examples of the data:
;
(define cars (list 'vw 'bmw 'audi 'saab 'geo))
(define (reals<10 x) (and (real? x) (<  x 10)))
(define (reals>=4 x) (and (real? x) (>= x  4)))

; Observation:
; The list representation can only be used for finite sets.
; The indicator-function representation can accomodate finite or infinite sets.





;; element-of?: ANY, inft-Set --> boolean
;; Is x in S?
;;
;; (Implementation note:
;;  compares via 'equal?' (not 'eq?') 
;;  if given a list-representation of a Set/infinite.)
;;
;  
;;
(define (element-of? x S)
  (cond [(list? S)      (not (boolean? (member x S)))]
        [(procedure? S) (S x)]))
  ;
  ; Not an issue unless reference-values are used:
  ; If we wanted to use eq? rather than equal?, 
  ; we'd use "memq" instead of "member".
  ; Either way, the indicator function implementation doesn't 
  ; have this ambiguity -- the function itself is given the
  ; input (possibly a reference), and decides the answer for itself.

; Tests:
;
(element-of? 'vw cars)   = true
(element-of? 'yugo cars) = false

(element-of?  4  reals<10)  = true
(element-of? 13  reals<10)  = false
(element-of? 'vw reals<10)  = false





;; intersect: Set, Set --> Set
;; union:     Set, Set --> Set
;;
;; Implementation note: the returned Set happens to
;; be represented as an indicator function, regardless of the input
;; representation.
;; (Not that the user of the abstract type "Set" cares.)
;;
;  
;;
(define (intersect A B)
   (lambda (elt) (and (element-of? elt A) (element-of? elt B))))

(define (union A B)
   (lambda (elt) (or  (element-of? elt A) (element-of? elt B))))


; Tests:
;
(element-of? 'vw   (union cars     reals<10)) = true
(element-of?  9    (union cars     reals<10)) = true
(element-of? 11    (union cars     reals<10)) = false
(element-of? 11    (union reals>=4 reals<10)) = true
(element-of?  3    (union reals>=4 reals<10)) = true
(element-of?  6    (union reals>=4 reals<10)) = true

(element-of? 'yugo (intersect cars     reals<10)) = false
(element-of? 'vw   (intersect cars     reals<10)) = false
(element-of?   6   (intersect reals>=4 reals<10)) = true
(element-of?  11   (intersect reals>=4 reals<10)) = false
(element-of?   3   (intersect reals>=4 reals<10)) = false







;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Doomed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; An attempt, which will be scotched by not being
;; able to implement subset? for inft-sets.
;; (This turns out to be a fundamental limit on computation -- not
;;  an artifact of our language, representation, etc.)
;; However, for finite sets, this code works like a charm.
;  
;; 

;; inft-set=?: set, set --> boolean
;;
(define (inft-set=? A B)  (and (subset? A B) (subset? B A)))
  ;
  ; This code directly parallels our (alternate) def'n of equal sets 
  ; -- happiness!

;; empty-set?: set --> boolean
;;
(define (empty-set? A)  (inft-set=? empty A)) 
  ;
  ; Pointed out: Could also write (subset? A empty).
  ; Empty is one possible representation of the empty set; what is another?



;; subset?: set, set --> boolean
;;
(define (subset? A B)
  (error 'subset? "Fundamentally can't implement subset? for infinite sets."))
;
; If we restrict ourselves to finite sets, then we could write subset?.
; We still would not want to change the code for set=? or empty-set? --
; The compiler can do any optimization; we'll keep our code clearly
; reflecting our definitions.
;
; See the reading (Rosen 1.7) for implementations of finite sets.




#|
;;;;;;;;;;;;;;;;; Aside: An object hierarchy for finite & infinite sets.
In a class system, how should classes inft-set and finite-set be arranged?
;  

(define-class Inft-set (extends Object)
   (public* element-of?)
   (static* union intersect))
   ; Make these 2-arg functions static, not methods,
   ; since neither of the two args have more importance than the other.

(define-class Finite-set (extends Inft-set)
   (inherit*  element-of? union intersect)
   (public*   subset? empty-set?)
   (static*   set=?)
   ; Make this 2-arg functions static, not methods,
   ; since neither of the two args have more importance than the other.
   )

(N.B. This isn't exactly drscheme's object syntax;
      see help-desk for the official details.)

It's a bit weird english, to say "Finite-set extends Inft-set";
clearly finite sets are a >restriction< of infinite sets.
However, in terms of behavior, we are extending the number of methods.

Indeed, the is-a relation certainly holds between these classes:
every Finite-set is-a Inft-set.
(Okay, maybe a better name would have been "Possibly-infinite-set", oh well.)
This is analagous to "class Cat extends Animal" -- Cats are a restricted 
type of Animal, but they have more behaviors than generic Animals,
such as shredOwnersOttoman! (a function with side-effects).

One annoying thing:
if we wanted, for Finite-sets, versions of union and
intersect that returned *finite* sets (rather than just Sets),
we'd just override those methods.
HOWEVER, most languages don't allow 
modifying the signature of the inherited function.
This is true even though:
- we want to express that Finite-set.union() *must* always return a 
  Finite-set, and 
- we are still meeting the original contract, 
  since every Finite-set is-a Inft-set.
This weakness of the type-system keeps us from properly expressing
the typing that we really want to enforce
(and, may force us to add type-casts to our code later -- ugly!).

|#



)  ; End module.
;