Because there's no obvious way to complete the tail. Any choice on how to do it would result in a non-obvious tail.
The trick is to explicitly lengthen your shortest list to match the length of the longest with values you expect.
If zip did that for you, you couldn't know what values it was filling in intuitively. Did it cycle the list? Did it repeat a mempty value? What is a mempty value for your type?
There's no implication in what zip does which one could use to intuit the way the tail would be lengthened, so the only reasonable thing to do is work with the values available rather than making some up your consumer may not expect.
Also remember you're referring to a very specific well known function with specific well known semantics. But that doesn't mean you can't make a similar but slightly different function. Just because there's a common function that does
x, doesn't mean you can't decide for your given purpose you want to do
Though remember the reason this and many other common FP style functions are common, is because they're simple and generalized so you can tweak your code to use them and get the behaviour you want. For instance, in C# you could just
IEnumerable<Tuple<T, U>> ZipDefaults(IEnumerable<T> first, IEnumerable<U> second)
return first.Count() < second.Count()
? first.Concat(Enumerable.Repeat(default(T), second.Count() - first.Count())).Zip(second)
: first.Zip(second.Concat(Enumerable.Repeat(default(U), first.Count() - second.count())))
Or other simple things. FP approaches make modifications so easy because you can reuse pieces as well as having implementations be so small as above that creating your own modified versions of things is exceedingly simple.