"Given two streams, form a new stream consisting of
 all entries where, for any given index in the resulting
 stream, the key of the entry is the element occurring 
 at the same index in the first stream, and the item is 
 the element occurring at the same index in the second 
 stream. The length of the resulting stream is the 
 length of the shorter of the two given streams.
 
 Thus:
 
     zipEntries(keys, items)[i] == keys[i] -> items[i]
 
 for every `0<=i<smallest(keys.size,items.size)`."
shared Iterable<<Key->Item>,KeyAbsent|ItemAbsent> 
zipEntries<Key,Item,KeyAbsent,ItemAbsent>
        (Iterable<Key,KeyAbsent> keys, 
         Iterable<Item,ItemAbsent> items)
        given Key satisfies Object
        given KeyAbsent satisfies Null
        given ItemAbsent satisfies Null
        => mapPairs(Entry<Key,Item>, keys, items);

"Given two streams, form a new stream consisting of
 all pairs where, for any given index in the resulting
 stream, the first element of the pair is the element 
 occurring at the same index in the first stream, and 
 the second element of the pair is the element occurring 
 at the same index in the second stream. The length of 
 the resulting stream is the length of the shorter of the 
 two given streams.
 
 Thus:
 
     zipPairs(xs, ys)[i] == [xs[i], ys[i]]
 
 for every `0<=i<smallest(xs.size,ys.size)`."
shared Iterable<[First,Second],FirstAbsent|SecondAbsent> 
zipPairs<First,Second,FirstAbsent,SecondAbsent>
        (Iterable<First,FirstAbsent> firstElements, 
         Iterable<Second,SecondAbsent> secondElements)
        given FirstAbsent satisfies Null
        given SecondAbsent satisfies Null
        => mapPairs((First first,Second second) => [first,second],
                firstElements, secondElements);

"Given a stream of values, and a stream of tuples, produce
 a new stream of tuples formed by prepending the values in
 the first stream to the tuples in the second stream. The 
 length of the resulting stream is the length of the shorter 
 of the two given streams.
 
 Thus:
 
     zip(heads, tails)[i] == [heads[i], *tails[i]]
 
 for every `0<=i<smallest(heads.size,tails.size)`."
shared Iterable<Tuple<Element|Head,Head,Tail>,HeadAbsent|TailAbsent> 
zip<Element,Head,Tail,HeadAbsent,TailAbsent>
        (Iterable<Head,HeadAbsent> heads, 
         Iterable<Tail,TailAbsent> tails)
        given Tail satisfies Element[]
        given HeadAbsent satisfies Null
        given TailAbsent satisfies Null
        => mapPairs(Tuple<Element|Head,Head,Tail>, heads, tails);