The proposed definition has one drawback: it is strict in its second argument.
It should be possible to make it lazy in its second argument while keeping the single-pass behavior, though. Something like this?
ZipList xs <|> ZipList ys = ZipList $ go xs ys 0
where
go [] ys n = drop n ys
go (x:xs) ys n = x : (go xs ys $! n + 1)