"""Abstract supertype of objects that contain other 
   values, called *elements*, where it is possible to 
   efficiently determine if a given value is an element. 
   `Category` does not satisfy `Container`, because it is 
   conceptually possible to have a `Category` whose 
   emptiness cannot be computed.
   
   The `in` operator may be used to determine if a value
   belongs to a `Category`:
   
       if ("hello" in "hello world") { ... }
       if (69 in 0..100) { ... }
       if (key->value in { for (n in 0..100) n.string->n**2 }) { ... }
   
   Ordinarily, `x==y` implies that `x in cat == y in cat`.
   But this contract is not required since it is possible
   to form a meaningful `Category` using a different
   equivalence relation. For example, an `IdentitySet` is
   a meaningful `Category`."""
by ("Gavin")
shared interface Category {
    
    "Determines if the given value belongs to this
     `Category`, that is, if it is an element of this
     `Category`.
     
     For most `Category`s, if `x==y`, then 
     `category.contains(x)` evaluates to the same
     value as `category.contains(y)`. However, it is
     possible to form a `Category` consistent with some 
     other equivalence relation, for example `===`. 
     Therefore implementations of `contains()` which do 
     not satisfy this relationship are tolerated."
    see (`function containsEvery`, `function containsAny`)
    shared formal Boolean contains(Object element);
    
    "Determines if every one of the given values belongs
     to this `Category`."
    see (`function contains`)
    shared default Boolean containsEvery({Object*} elements) {
        for (element in elements) {
            if (!contains(element)) {
                return false;
            }
        }
        else {
            return true;
        }
    }

    "Determines if any one of the given values belongs 
     to this `Category`"
    see (`function contains`)
    shared default Boolean containsAny({Object*} elements) {
        for (element in elements) {
            if (contains(element)) {
                return true;
            }
        }
        else {
            return false;
        }
    }

}