So, to clarify, Iterators aren't a thing in themselves. Iteration is an interface, and to call something an iterator just means that you can put it in a for loop. Tasks and Lazy Lists are both iterators; so are arrays, sets, dictionaries, and a whole bunch of other things. But although you can use them in a similar way if you want to, they are all designed to solve very different problems.
Now, Tasks and Lazy Lists do look similar in that you can produce and consume a stream of values with both, but conceptually they are quite different - Tasks are a mechanism for control flow, whereas Lazy Lists are a data structure. Perhaps you could call them the procedural and functional analogies of each other. I can't tell you what's best for you, but if you're thinking of Tasks as representing a sequence of data, then there's a good chance you'll find Lazy Lists easier to reason about. For example, consider the partition() function. In Lazy.jl terms this splits a single list into a list of lists - it's fairly easy to visualise this: > partition(3, seq(1:9)) List: (1 2 3) (4 5 6) (7 8 9) If you wanted to write partition() for Tasks, you'd end up with tasks that produce tasks. I don't know about you, but that gives me a headache. You'll also notice that working with general iterators takes a lot of work; consider the Iterators.jl version of take(), which takes about twenty lines, versus the two-liner in Lazy.jl. Some things are simply impossible to do generically, like flatten(). That's not to say that Tasks aren't useful - they're better if you want to do more things in terms of control flow and less in terms of manipulating the data itself, for example. Both Tasks and Lazy Lists are extremely powerful, but each within their own scope - hence it's useful to have both. Is this roughly what you were looking for? Let me know if I've missed anything.