"A possibly-empty, immutable sequence of values. The type 
 `Sequential<Element>` may be abbreviated `[Element*]` or 
 `Element[]`. 
 
 `Sequential` has two enumerated subtypes:
 
 - [[Empty]], abbreviated `[]`, represents an empty 
   sequence, and
 - [[Sequence]]`<Element>`, abbreviated `[Element+]` 
   represents a non-empty sequence, and has the very 
   important subclass [[Tuple]]."
see (`class Tuple`)
tagged("Sequences")
shared interface Sequential<out Element=Anything>
        of []|[Element+]
        satisfies List<Element> & 
                  Ranged<Integer,Element,Element[]> {
    
    "The strictly-positive length of this sequence, that is, 
     the number of elements in this sequence."
    shared actual formal Integer size;
    
    "A sequence containing all indexes of this sequence,
     that is, every index in the range `0:sequence.size`."
    shared actual default Integer[] keys => 0:size;
    
    "This sequence."
    shared actual default Element[] sequence() => this;
    
    "The rest of the sequence, without the first element."
    shared actual formal Element[] rest;
    
    "A sequence containing the elements of this sequence in
     reverse order to the order in which they occur in this
     sequence, or the [[empty sequence|empty]] if this
     sequence is the empty sequence."
    shared actual formal Element[] reversed;
    
    "Produces a sequence formed by repeating the elements of
     this sequence the given [[number of times|times]], or
     the [[empty sequence|empty]] if `times<=0` or if this
     sequence is the empty sequence."
    shared actual formal Element[] repeat(Integer times);
    
    "Select the first elements of this sequence, returning 
     a sequence no longer than the given length. If this 
     sequence is shorter than the given length, return this 
     sequence. Otherwise return a sequence of the given 
     length. If `length<=0` return an [[Empty]] sequence."
    shared actual default Element[] initial(Integer length)
            => this[...length-1];
    
    "Select the last elements of the sequence, returning a 
     sequence no longer than the given length. If this 
     sequence is shorter than the given length, return this 
     sequence. Otherwise return a sequence of the given 
     length."
    shared actual default Element[] terminal(Integer length)
            => this[size-length...]; 
    
    "This sequence."
    shared actual default Element[] clone() => this;
    
    "Trim the elements satisfying the given predicate
     function from the start and end of this sequence, 
     returning a sequence no longer than this sequence."
    shared actual default 
    Element[] trim(
        "The predicate function that determines if an 
         element at the start or end of this sequence should
         be trimmed"
        Boolean trimming(Element&Object element))
            => super.trim(trimming).sequence(); //TODO: inefficient?
    
    "Trim the elements satisfying the given predicate
     function from the start of this sequence, returning 
     a sequence no longer than this sequence."
    shared actual default 
    Element[] trimLeading(
        "The predicate function that determines if an 
         element at the start of this sequence should be 
         trimmed"
        Boolean trimming(Element&Object element))
            => super.trimLeading(trimming).sequence(); //TODO: inefficient?
    
    "Trim the elements satisfying the given predicate
     function from the end of this sequence, returning a 
     sequence no longer than this sequence."
    shared actual default 
    Element[] trimTrailing(
        "The predicate function that determines if an 
         element at the end of this sequence should be 
         trimmed"
        Boolean trimming(Element&Object element))
            => super.trimTrailing(trimming).sequence(); //TODO: inefficient?
    
    "Return two sequences, the first containing the elements
     that occur before the given [[index]], the second with
     the elements that occur after the given `index`. If the
     given `index` is outside the range of indices of this
     list, one of the returned sequences will be empty."
    shared actual default 
    [Element[],Element[]] slice(Integer index)
            => [this[...index-1], this[index...]];
    
    "Returns a new sequence that starts with the specified
     [[element]], followed by the elements of this sequence,
     in the order they occur in this sequence."
    see (`function prepend`,
         `function withTrailing`,
         `function follow`)
    shared formal 
    [Other,Element*] withLeading<Other>(
        "The first element of the resulting sequence."
        Other element);
    
    "Returns a new sequence that starts with the elements of 
     this sequence, in the order they occur in this sequence, 
     and ends with the specified [[element]]."
    see (`function append`,
         `function withLeading`)
    shared formal 
    [Element|Other+] withTrailing<Other>(
        "The last element of the resulting sequence."
        Other element);
    
    "Return a sequence containing the elements of this 
     sequence, in the order in which they occur in this 
     sequence, followed by the given [[elements]], in the 
     order in which they occur in the given sequence."
    see (`function prepend`,
         `function withTrailing`,
         `function concatenate`,
         `function chain`)
    shared formal 
    [Element|Other*] append<Other>(Other[] elements);
    
    "Return a sequence containing the given [[elements]], in 
     the order in which they occur in the given sequence,
     followed by the elements of this sequence, in the order 
     in which they occur in this sequence."
    see (`function append`,
         `function withLeading`,
         `function concatenate`)
    shared formal 
    [Element|Other*] prepend<Other>(Other[] elements);
    
    "A string of form `\"[ x, y, z ]\"` where `x`, `y`, and 
     `z` are the `string` representations of the elements of 
     this collection, as produced by the iterator of the 
     collection, or the string `\"{}\"` if this collection 
     is empty. If the collection iterator produces the value 
     `null`, the string representation contains the string 
     `\"null\"`."
    shared actual default 
    String string 
            => empty then "[]" else "[``commaList(this)``]";
    
}