Because the suggested duplicates answer most of this, I will focus on the questions in your followup comment.
1) why is the standard implementation for fixed n = 2
zipWith
is for 2 arguments, and repeat
is for 0 arguments. This is enough to get arbitrary-arity zips. For example, the 1 argument version (also called map
) can be implemented as
map f = zipWith ($) (repeat f)
and the 3 argument version as
zipWith3 f = (.) (zipWith ($)) . zipWith f
and so on. There is a pretty pattern to the implementations of larger zips (admittedly not obvious from this small sample size). This result is analogous to the one in CT which says that any category with 0-ary and 2-ary products has all finitary products.
The other half of the answer, I suppose, is that type-level numbers (which are the most frequent implementation technique for arbitrary-arity zips) are possible but annoying to use, and avoiding them tends to reduce both term- and type-level noise.
2) I need to pass the number of lists, that's unwieldy
Use ZipList
. You don't need to pass the number of lists (though you do need to write one infix operator per list -- a very light requirement, I think, as even in Python you need a comma between each list).
Empirically: I have not found arbitrary-arity zips such a common need that I would label it "unwieldy".
3) even if I define my own zip, there will be collisions with Prelude.zip.
So pick another name...?