Reputation: 4758
In F# if one tries to zip two lists of different lengths one gets an error:
List.zip [1..4] [1..3]
// System.ArgumentException: The lists had different lengths.
However, it is very easy to define an alternative definition of zip that accepts two argument lists of different lengths:
let rec zip' (xs: 'T list) (ys: 'T list) =
match (xs, ys) with
| ([], _) -> []
| (_, []) -> []
| ((z::zs), (w::ws)) -> (z, w) :: zip' zs ws
zip' [1..4] [1..3]
// val it : (int * int) list = [(1, 1); (2, 2); (3, 3)]
Is there a good reason not to use this alternative definition? Why wasn't it adopted in the first place?
Upvotes: 6
Views: 1657
Reputation: 243106
This is, indeed, a bit confusing because there is a mismatch between List.zip
(which does not allow this) and Seq.zip
(which truncates the longer list).
I think that zip
which works only on lists of equal length is a reasonable default behaviour - if it automatically truncated data, there is a realistic chance that you would accidentally lose some useful data when using zip
which might cause subtle bugs.
The fact that Seq.zip
truncates the longer list is only sensible because sequences are lazy and so, by design, when I define a sequence I expect that the consumer might not read it all.
In summary, I think the behaviour difference is based on "what is the most sensible thing to do for a given data structure", but I do think having two names for the operations would make a lot more sense than calling both zip
(alas, that's pretty much impossible to change now).
Upvotes: 16