"Abstract supertype of objects which associate values 
 with keys. `Correspondence` does not satisfy `Category`,
 since in some cases—`List`, for example—it is 
 convenient to consider the subtype a `Category` of its
 values, and in other cases—`Map`, for example—it 
 is convenient to treat the subtype as a `Category` of its
 entries.
 
 The item corresponding to a given key may be obtained 
 from a `Correspondence` using the item operator:
 
     value bg = settings[\"backgroundColor\"] else white;
 
 The `get()` operation and item operator result in an
 optional type, to reflect the possibility that there is
 no item for the given key."
see (`interface Map`, `interface List`, `interface Category`)
by ("Gavin")
shared interface Correspondence<in Key, out Item>
        given Key satisfies Object {
    
    "Returns the value defined for the given key, or 
     `null` if there is no value defined for the given 
     key."
    see (`function Correspondence.items`)
    shared formal Item? get(Key key);
    
    "Determines if there is a value defined for the 
     given key."
    see (`function Correspondence.definesAny`, 
         `function Correspondence.definesEvery`, 
         `value Correspondence.keys`)
    shared default Boolean defines(Key key) => 
            get(key) exists;
    
    "The `Category` of all keys for which a value is 
     defined by this `Correspondence`."
    see (`function Correspondence.defines`)
    shared default Category keys => Keys(this);
    
    "Determines if this `Correspondence` defines a value
     for every one of the given keys."
    see (`function Correspondence.defines`)
    shared default Boolean definesEvery({Key*} keys) {
        for (key in keys) {
            if (!defines(key)) {
                return false;
            }
        }
        else {
            return true;
        }
    }
    
    "Determines if this `Correspondence` defines a value
     for any one of the given keys."
    see (`function Correspondence.defines`)
    shared default Boolean definesAny({Key*} keys) {
        for (key in keys) {
            if (defines(key)) {
                return true;
            }
        }
        else {
            return false;
        }
    }
    
    "Returns the items defined for the given keys, in
     the same order as the corresponding keys."
    see (`function Correspondence.get`)
    shared default Item?[] items({Key*} keys) =>
            [ for (key in keys) get(key) ];
    
}