I'm struggling to understand why there are two different structures in Swift that are almost the same.
Edit: I think I still do not understand what "lazy" in sequence means... F.e. take this code that uses SequenceOf that supposedly is not lazy:
func myMap<S: SequenceType, V>(source: S,
selector: S.Generator.Element -> V) -> SequenceOf<V> {
let seq = SequenceOf {
_ -> GeneratorOf<V> in
var gen = source.generate()
return GeneratorOf {
let v = gen.next()
println(v)
return v == nil ? nil : selector(v!)
}
}
return seq
}
Let's call it with
let a = myMap([1, 2, 3], { $0 * 2 })
var gen = a.generate()
let v1 = gen.next()
let v2 = gen.next()
It prints
Optional(1)
Optional(2)
Looks lazy to me...
Edit #2:
When using map over a lazy sequence it seems to be eagerly evaluating elements anyway:
struct TransientView<S: SequenceType> : SequenceType {
private let seq: S
init(_ seq: S) {
self.seq = seq
}
func generate()
-> GeneratorOf<S.Generator.Element> {
var g = seq.generate()
return GeneratorOf {
println("next")
return g.next()
}
}
}
let seq = lazy(map(TransientView([1, 2, 3]), { $0 * 2 }))
prints "next" 4 times...
Edit #3. Here is my current take on it: It would be wrong to say "SequenceOf is not lazy". It is rather "SequenceOf is extended with non-lazy .map, .filter, etc". It is entirely possible to write lazy versions of map, filer, etc that would apply to any sequence, including SequenceOf. But, Apple decided to apply the "lazy" paradigm not only to instances of sequences, but to sequence elements as well - so if you declare sequence variable as lazy, LazySequence is used and as such extensions are lazy. I think this is wrong approach and lazy declaration should not be transferred to elements - instead elements should be kept lazy as long as it is possible. It is easy to convert lazy to eager, but not possible otherwise.
Is SequenceOf not lazy?
Correct. It is not lazy. That's why the lazy forms exist.
What are the intended uses for each?
Airpseed Velocity probably has the most comprehensive discussion of the various types. SequenceOf
provides easy ways to generate sequences from a closure. It also provides a sort of "sequence typecast" to convert one sequence type to another.
LazySequence
is primarily created using the lazy
function. Airspeed Velocity's Working at being lazy gives a nice intro. Its purpose is to avoid generating elements before they're actually required, which is particularly useful for infinite sequences, but is useful in any case that you may not need all the elements, and they are non-trivial to generate.
Did I mention you should read Airspeed Velocity if you want deep-dives on this stuff? But it is still worth keeping in mind that we only have what we can infer from the headers, glean from devforum discussions, and intuit from what we else we know about Swift. The lower-level types are not well documented yet, and aren't part of any of the "official" docs, and they've changed several times over the betas. So it's not always easy to know precisely what the Swift team intends for them in versions to come. This is the best we know so far.
EDIT: As I note in the comments, there is no map
function that takes and returns a LazySequence
in 6.1b3. There's only a map
method on LazySequence
. But we can build one if we want, and maybe they'll add it eventually:
func map<S: SequenceType, U>(source: LazySequence<S>, transform: S.Generator.Element -> U) -> LazySequence<MapSequenceView<S, U>> {
return source.map(transform)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With