Is there a way to implement `ZipSequence.Iterator`'s `next()` method from SE-0398

I've been playing around with parameter packs and trying to implement the body of ZipSequence.Iterator's next() method from SE-0398 with little success.

The code from the proposal for reference:

struct ZipSequence<each S: Sequence>: Sequence {
	typealias Element = (repeat (each S).Element)

	let seq: (repeat each S)

	func makeIterator() -> Iterator {
		return Iterator(iter: (repeat (each seq).makeIterator()))
	}

	struct Iterator: IteratorProtocol {
		typealias Element = (repeat (each S).Element)

		var iter: (repeat (each S).Iterator)

		mutating func next() -> Element? {
			return ???
		}
	}
}

func zip<each S>(
	_ seq: repeat each S
) -> ZipSequence<repeat each S> where repeat each S: Sequence {
	ZipSequence(seq: (repeat each seq))
}

I've tried using (repeat (each iter).next()) which results in the error `Cannot use mutating member on immutable value of type 'τ_1_0.Iterator'.

is there a way to implement this or does this require pack iteration to be implemented?

1 Like

From [Pitch] Parameter Packs - #93 by Slava_Pestov

4 Likes

A few weeks ago @hborla came up with an interesting workaround for the lack of mutable packs, sufficient to implement a ZipIterator. Behold:

enum Stop: Error {
  case stop
}

struct ZipIterator<each T: IteratorProtocol>: IteratorProtocol {
  var iter: (repeat each T)

  init(_ iter: repeat each T) {
    self.iter = (repeat each iter)
  }

  mutating func next() -> (repeat (each T).Element)? {
    func step<I: IteratorProtocol>(_ iter: I) throws -> (I, I.Element) {
      var iter2 = iter
      guard let next = iter2.next() else { throw Stop.stop }
      return (iter2, next)
    }

    do {
      let result: (repeat (each T, (each T).Element)) = (repeat try step(each iter))
      iter = (repeat (each result).0)
      return (repeat (each result).1)
    } catch {
      return nil
    }
  }
}

var x = ZipIterator([1, 2, 3].makeIterator(), ["hi", "hello", "hey"].makeIterator())
print(x.next())
print(x.next())
print(x.next())
print(x.next())

Making this ergonomic is basically half of the parameter packs roadmap...

13 Likes