Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SequenceOf and LazySequence - what is the difference and intended use?

Tags:

swift

I'm struggling to understand why there are two different structures in Swift that are almost the same.

  • Is SequenceOf not lazy?
  • What are the intended uses for each?

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.

like image 462
Sergey Aldoukhov Avatar asked Sep 22 '14 20:09

Sergey Aldoukhov


1 Answers

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)
}
like image 161
Rob Napier Avatar answered Jan 01 '23 10:01

Rob Napier