The simplest on-demand sequences are built out of just functions: a sequence is a function that, when called, either tells you that the sequence is empty or give you the first element and the rest as a sequence (a function to be called again). In Batteries, this is done by
Seq, and this is what you should use if you need nothing more than that (and its API suits you, of course).
LazyList adds memoization: if you have the same sequence value and ask for its head element twice,
Seq will call the function twice which may incur some recomputation.
Lazy values are memoized, so that on the second call they are not recomputed but just returned directly (but this requires some book-keeping that has some performance impact). If you are going to access the same elements several times,
LazyList may be better.
Enum, on the contrary, is “more imperative”: once you access an element once, it is consumed, removed from the enum, and you cannot get it back. This in theory guarantees some nice memory property (you cannot leak memory by mistakenly keeping a reference to the head of the sequence), but in practice makes the implement messy, somewhat unreliable, and not very efficient.