Soldalma
Soldalma

Reputation: 4758

Why can't I zip two lists of different lengths?

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

Answers (1)

Tomas Petricek
Tomas Petricek

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

Related Questions