I'm thinking about writing a Delphi implementation of the functional Zip routine, which takes two lists and outputs a list of pairs of elements. So, feeding it [1, 2, 3] and ['a', 'b', 'c'] would give [(1, 'a'), (2, 'b'), (3, 'c')] as the result. Which is great if both inputs are exactly the same length, like they are in every demo I've seen of this function online. But what if the first one was [1, 2, 3, 4]? What should the output be? How is this case handled in other implementations in other languages?
There's no "right" or "wrong" way to do this, the implementation details are up to you. You can take several approaches:
1) F# approach: throw an exception.
2) Haskell and Python approach: Truncate output to minimum length of your inputs.
zip [1; 2; 3] ['a'; 'b'; 'c'; 'd'; 'e']
= [ (1, 'a'); (2, 'b'); (3, 'c')]
It can be occasionally useful to truncate, as is normally the case when you zip a finite and infinite sequence.
3) Ruby approach: zero or nil out unavailable values:
zip [1; 2; 3] ['a'; 'b'; 'c'; 'd'; 'e']
= [ (1, 'a'); (2, 'b'); (3, 'c'); (nil, 'd'); (nil, 'e')]
4) Shorten tuples 2- and 1-tuples as needed:
zip [1; 2; 3] ['a'; 'b'; 'c'; 'd'; 'e']
= [ (1, 'a'); (2, 'b'); (3, 'c'); ('d'); ('e')]
I don't know any language which does this.
Python truncates to the length of the minimum sequence. That works for me.
A common thing to do is to zip a list with its own tail. For example to turn a list of points into a path that visits those points. The tail is obviously one shorter than the list, but this is certainly not an exceptional case. Another common thing is to zip a list with all of its tails to get a list of unordered pairs that can be constructed from the list (to construct a complete graph, for example:
liftM2 (=<<) zip tails
This would be really difficult if zip
threw exceptions or returned nulls. The expected behaviour therefore is to truncate the output to the length of the shorter list. This is consistent with the type of the function.