Feels like the discussion is running in circles. One of the things that bothers me a bit, is that discussing away bugs seems a bit simpler in Julia.
First, its interfaces are usually not formally defined or enforced and accordingly one can always argue whether its a bug or not. E.g., what would you expect when calling cycle
on a stateful iterator: a) It caches all values and reuses those (which could lead to unexpected memory leaks – just search for lazy IO in Haskell) or b) it throws an error (making it well defined, but essentially useless) or c) it does something which you might or might not expect (putting it in the ream of undefined behaviour which is morally defensible as no correct behaviour seems possible anyways)?
Secondly, the assumptions behind generic interfaces are also not well specified and some implementations make slightly different choices than others. I would certainly agree that the implementation
reverse(z::Zip) = Zip(Base.map(reverse, z.is)) # n.b. we assume all iterators are the same length
is wrong as its assumption is squarely at odds with the docstring of zip
zip(iters...)
Run multiple iterators at the same time, until any of them is exhausted.
Generic programming enables very composable code, but also requires higher-levels of abstractions to work flawlessly, and at points, some Julia code appears a bit careless in what can be assumed and what not. While I don’t expect Haskell like abstractions and laws, some documentation around the assumed invariances in generic interfaces could be helpful at times.