I've been trying to figure out why the following code is ambiguous...
public func product <T1: Sequence, T2: Sequence> (_ sequence1: T1, _ sequence2: T2) ->
AnySequence<(T1.Element, T2.Element)> {
return AnySequence(
sequence1.flatMap { element1 in
sequence2.map { element2 in
(element1, element2)
}
}
)
}
public func product <T1: LazySequenceProtocol, T2: LazySequenceProtocol> (_ sequence1: T1, _ sequence2: T2) ->
LazySequence<AnySequence<(T1.Element, T2.Element)>> {
return AnySequence(
sequence1.flatMap { element1 in
sequence2.map { element2 in
(element1, element2)
}
}
).lazy
}
...when I call it with two lazy sequences and a call to makeIterator
EXAMPLE.
_ = product([1, 2].lazy, [3, 4].lazy).makeIterator()
Yet, the following code doesn't have this ambiguity...
public struct Product2Sequence <T1: Sequence, T2: Sequence>: Sequence {
public typealias Element = (T1.Element, T2.Element)
public typealias Iterator = AnyIterator<Element>
private let iterator: Iterator
internal init (_ sequence1: T1, _ sequence2: T2) {
self.iterator = AnyIterator(
sequence1.flatMap { element1 in
sequence2.map { element2 in
(element1, element2)
}
}.makeIterator()
)
}
public func makeIterator () -> Iterator {
return self.iterator
}
}
public struct LazyProduct2Sequence <T1: LazySequenceProtocol, T2: LazySequenceProtocol>: LazySequenceProtocol {
public typealias Element = (T1.Element, T2.Element)
public typealias Iterator = AnyIterator<Element>
private let iterator: Iterator
internal init (_ sequence1: T1, _ sequence2: T2) {
self.iterator = AnyIterator(
sequence1.flatMap { element1 in
sequence2.map { element2 in
(element1, element2)
}
}.makeIterator()
)
}
public func makeIterator () -> Iterator {
return self.iterator
}
}
public func product <T1: Sequence, T2: Sequence> (_ sequence1: T1, _ sequence2: T2) -> Product2Sequence<T1, T2> {
return Product2Sequence(sequence1, sequence2)
}
public func product <T1: LazySequenceProtocol, T2: LazySequenceProtocol> (_ sequence1: T1, _ sequence2: T2) ->
LazyProduct2Sequence<T1, T2> {
return LazyProduct2Sequence(sequence1, sequence2)
}
...when I call it with two lazy sequences and a call to makeIterator
EXAMPLE.
_ = product([1, 2].lazy, [3, 4].lazy).makeIterator()
My reasoning is that a lazy sequence conforms both to LazySequenceProtocol
and Sequence
so the type system doesn't know which product
to choose. But by that definition the second version should also not work.
I'm using Swift 4.0.
What makes the second version work?
This is a bug that was resolved with 4.1 (see https://bugs.swift.org/browse/SR-4509). There used to be no way for the type solver to choose between Sequence
and LazySequenceProtocol
, as the former obviously conforms to the latter.
I can't say for sure why your second version does work with 4.0 and have no evidence to support my assumptions, but I would guess it has something to do with the type solver being able to get more information from more concrete return types.
Anyway, LazySequenceProtocol
is now preferred so as to preserve laziness as long as possible. Your code works as expected with Swift 4.1.
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