使用函数时编译时间长 (Swift 4)
Long compile time when using a function (Swift 4)
以下代码在合理的时间内自行编译EXAMPLE:
public struct LazyProduct6Sequence <
T1: LazySequenceProtocol, T2: LazySequenceProtocol, T3: LazySequenceProtocol,
T4: LazySequenceProtocol, T5: LazySequenceProtocol, T6: LazySequenceProtocol
>: LazySequenceProtocol {
public typealias Element = (T1.Element, T2.Element, T3.Element, T4.Element, T5.Element, T6.Element)
public typealias Iterator = AnyIterator<Element>
private let iterator: Iterator
internal init (
_ sequence1: T1, _ sequence2: T2, _ sequence3: T3,
_ sequence4: T4, _ sequence5: T5, _ sequence6: T6
) {
self.iterator = AnyIterator(
sequence1.flatMap { element1 in
sequence2.flatMap { element2 in
sequence3.flatMap { element3 in
sequence4.flatMap { element4 in
sequence5.flatMap { element5 in
sequence6.map { element6 in
(element1, element2, element3, element4, element5, element6)
}
}
}
}
}
}.makeIterator()
)
}
public func makeIterator () -> Iterator {
return self.iterator
}
}
public func product <
T1: LazySequenceProtocol, T2: LazySequenceProtocol, T3: LazySequenceProtocol,
T4: LazySequenceProtocol, T5: LazySequenceProtocol, T6: LazySequenceProtocol
> (
_ sequence1: T1, _ sequence2: T2, _ sequence3: T3,
_ sequence4: T4, _ sequence5: T5, _ sequence6: T6
) -> LazyProduct6Sequence<T1, T2, T3, T4, T5, T6> {
return LazyProduct6Sequence(sequence1, sequence2, sequence3, sequence4, sequence5, sequence6)
}
但是,在编译使用它的代码时,大约需要40秒才能编译(或根本拒绝编译)EXAMPLE:
_ = product([1, 2].lazy, [3, 4].lazy, [5, 6].lazy, [7, 8].lazy, [9, 10].lazy, [11, 12].lazy)
为什么编译要花那么多时间?
据我所知,这与 Swift 的类型推断系统有关。向每个闭包添加显式 return 类型并没有多大帮助,因为编译时间几乎保持不变。但是当我向使用函数 EXAMPLE:
的赋值中添加显式类型时,编译几乎是瞬时的
let sequence: LazyProduct6Sequence<
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>
> = product(
[1, 2].lazy,
[3, 4].lazy,
[5, 6].lazy,
[7, 8].lazy,
[9, 10].lazy,
[11, 12].lazy
)
let iterator = sequence.makeIterator()
while let element = iterator.next() {
print(element)
}
显然这并不理想而且很丑。
我不知道为什么会这样,因为只有一个函数匹配表达式。
可能值得一提的是,对于较低的 arities,编译时间会减少。如果我超载 product
也需要 eager Sequence
s 那么编译会冻结我的机器。
编辑:从那以后我发现这些类型的 Sequence
s 默认情况下应该是惰性的。使用与 Swift 的 zip
相同的命名约定修改我的函数,上面的示例变为:
public struct Product6Iterator <Sequence1: Sequence, Sequence2: Sequence, Sequence3: Sequence, Sequence4: Sequence,
Sequence5: Sequence, Sequence6: Sequence>: IteratorProtocol {
public typealias Element = (Sequence1.Element, Sequence2.Element, Sequence3.Element, Sequence4.Element,
Sequence5.Element, Sequence6.Element)
private let iterator: AnyIterator<Element>
internal init (_ sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: Sequence3, _ sequence4: Sequence4,
_ sequence5: Sequence5, _ sequence6: Sequence6) {
self.iterator = AnyIterator(
sequence1.lazy.flatMap { element1 in
sequence2.lazy.flatMap { element2 in
sequence3.lazy.flatMap { element3 in
sequence4.lazy.flatMap { element4 in
sequence5.lazy.flatMap { element5 in
sequence6.lazy.map { element6 in
(element1, element2, element3, element4, element5, element6)
}
}
}
}
}
}.makeIterator()
)
}
public mutating func next () -> Element? {
return self.iterator.next()
}
}
public struct Product6Sequence <Sequence1: Sequence, Sequence2: Sequence, Sequence3: Sequence, Sequence4: Sequence,
Sequence5: Sequence, Sequence6: Sequence>: Sequence {
public typealias Iterator = Product6Iterator<Sequence1, Sequence2, Sequence3, Sequence4, Sequence5, Sequence6>
public typealias Element = Iterator.Element
private let sequence1: Sequence1
private let sequence2: Sequence2
private let sequence3: Sequence3
private let sequence4: Sequence4
private let sequence5: Sequence5
private let sequence6: Sequence6
internal init (_ sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: Sequence3, _ sequence4: Sequence4,
_ sequence5: Sequence5, _ sequence6: Sequence6) {
self.sequence1 = sequence1
self.sequence2 = sequence2
self.sequence3 = sequence3
self.sequence4 = sequence4
self.sequence5 = sequence5
self.sequence6 = sequence6
}
public func makeIterator () -> Iterator {
return Iterator(sequence1, sequence2, sequence3, sequence4, sequence5, sequence6)
}
}
public func product <Sequence1: Sequence, Sequence2: Sequence, Sequence3: Sequence, Sequence4: Sequence,
Sequence5: Sequence, Sequence6: Sequence> (_ sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: Sequence3,
_ sequence4: Sequence4, _ sequence5: Sequence5, _ sequence6: Sequence6) -> Product6Sequence<Sequence1, Sequence2,
Sequence3, Sequence4, Sequence5, Sequence6> {
return sequence1.product(sequence2, sequence3, sequence4, sequence5, sequence6)
}
public extension Sequence {
func product <Sequence2: Sequence, Sequence3: Sequence, Sequence4: Sequence, Sequence5: Sequence,
Sequence6: Sequence> (_ sequence2: Sequence2, _ sequence3: Sequence3, _ sequence4: Sequence4,
_ sequence5: Sequence5, _ sequence6: Sequence6) -> Product6Sequence<Self, Sequence2, Sequence3, Sequence4,
Sequence5, Sequence6> {
return Product6Sequence(self, sequence2, sequence3, sequence4, sequence5, sequence6)
}
}
这个以及其他类似的 Sequence
扩展可以在我创建的名为 SequenceExtensions.
的库中找到
以下代码在合理的时间内自行编译EXAMPLE:
public struct LazyProduct6Sequence <
T1: LazySequenceProtocol, T2: LazySequenceProtocol, T3: LazySequenceProtocol,
T4: LazySequenceProtocol, T5: LazySequenceProtocol, T6: LazySequenceProtocol
>: LazySequenceProtocol {
public typealias Element = (T1.Element, T2.Element, T3.Element, T4.Element, T5.Element, T6.Element)
public typealias Iterator = AnyIterator<Element>
private let iterator: Iterator
internal init (
_ sequence1: T1, _ sequence2: T2, _ sequence3: T3,
_ sequence4: T4, _ sequence5: T5, _ sequence6: T6
) {
self.iterator = AnyIterator(
sequence1.flatMap { element1 in
sequence2.flatMap { element2 in
sequence3.flatMap { element3 in
sequence4.flatMap { element4 in
sequence5.flatMap { element5 in
sequence6.map { element6 in
(element1, element2, element3, element4, element5, element6)
}
}
}
}
}
}.makeIterator()
)
}
public func makeIterator () -> Iterator {
return self.iterator
}
}
public func product <
T1: LazySequenceProtocol, T2: LazySequenceProtocol, T3: LazySequenceProtocol,
T4: LazySequenceProtocol, T5: LazySequenceProtocol, T6: LazySequenceProtocol
> (
_ sequence1: T1, _ sequence2: T2, _ sequence3: T3,
_ sequence4: T4, _ sequence5: T5, _ sequence6: T6
) -> LazyProduct6Sequence<T1, T2, T3, T4, T5, T6> {
return LazyProduct6Sequence(sequence1, sequence2, sequence3, sequence4, sequence5, sequence6)
}
但是,在编译使用它的代码时,大约需要40秒才能编译(或根本拒绝编译)EXAMPLE:
_ = product([1, 2].lazy, [3, 4].lazy, [5, 6].lazy, [7, 8].lazy, [9, 10].lazy, [11, 12].lazy)
为什么编译要花那么多时间?
据我所知,这与 Swift 的类型推断系统有关。向每个闭包添加显式 return 类型并没有多大帮助,因为编译时间几乎保持不变。但是当我向使用函数 EXAMPLE:
的赋值中添加显式类型时,编译几乎是瞬时的let sequence: LazyProduct6Sequence<
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>,
LazyRandomAccessCollection<[Int]>
> = product(
[1, 2].lazy,
[3, 4].lazy,
[5, 6].lazy,
[7, 8].lazy,
[9, 10].lazy,
[11, 12].lazy
)
let iterator = sequence.makeIterator()
while let element = iterator.next() {
print(element)
}
显然这并不理想而且很丑。
我不知道为什么会这样,因为只有一个函数匹配表达式。
可能值得一提的是,对于较低的 arities,编译时间会减少。如果我超载 product
也需要 eager Sequence
s 那么编译会冻结我的机器。
编辑:从那以后我发现这些类型的 Sequence
s 默认情况下应该是惰性的。使用与 Swift 的 zip
相同的命名约定修改我的函数,上面的示例变为:
public struct Product6Iterator <Sequence1: Sequence, Sequence2: Sequence, Sequence3: Sequence, Sequence4: Sequence,
Sequence5: Sequence, Sequence6: Sequence>: IteratorProtocol {
public typealias Element = (Sequence1.Element, Sequence2.Element, Sequence3.Element, Sequence4.Element,
Sequence5.Element, Sequence6.Element)
private let iterator: AnyIterator<Element>
internal init (_ sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: Sequence3, _ sequence4: Sequence4,
_ sequence5: Sequence5, _ sequence6: Sequence6) {
self.iterator = AnyIterator(
sequence1.lazy.flatMap { element1 in
sequence2.lazy.flatMap { element2 in
sequence3.lazy.flatMap { element3 in
sequence4.lazy.flatMap { element4 in
sequence5.lazy.flatMap { element5 in
sequence6.lazy.map { element6 in
(element1, element2, element3, element4, element5, element6)
}
}
}
}
}
}.makeIterator()
)
}
public mutating func next () -> Element? {
return self.iterator.next()
}
}
public struct Product6Sequence <Sequence1: Sequence, Sequence2: Sequence, Sequence3: Sequence, Sequence4: Sequence,
Sequence5: Sequence, Sequence6: Sequence>: Sequence {
public typealias Iterator = Product6Iterator<Sequence1, Sequence2, Sequence3, Sequence4, Sequence5, Sequence6>
public typealias Element = Iterator.Element
private let sequence1: Sequence1
private let sequence2: Sequence2
private let sequence3: Sequence3
private let sequence4: Sequence4
private let sequence5: Sequence5
private let sequence6: Sequence6
internal init (_ sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: Sequence3, _ sequence4: Sequence4,
_ sequence5: Sequence5, _ sequence6: Sequence6) {
self.sequence1 = sequence1
self.sequence2 = sequence2
self.sequence3 = sequence3
self.sequence4 = sequence4
self.sequence5 = sequence5
self.sequence6 = sequence6
}
public func makeIterator () -> Iterator {
return Iterator(sequence1, sequence2, sequence3, sequence4, sequence5, sequence6)
}
}
public func product <Sequence1: Sequence, Sequence2: Sequence, Sequence3: Sequence, Sequence4: Sequence,
Sequence5: Sequence, Sequence6: Sequence> (_ sequence1: Sequence1, _ sequence2: Sequence2, _ sequence3: Sequence3,
_ sequence4: Sequence4, _ sequence5: Sequence5, _ sequence6: Sequence6) -> Product6Sequence<Sequence1, Sequence2,
Sequence3, Sequence4, Sequence5, Sequence6> {
return sequence1.product(sequence2, sequence3, sequence4, sequence5, sequence6)
}
public extension Sequence {
func product <Sequence2: Sequence, Sequence3: Sequence, Sequence4: Sequence, Sequence5: Sequence,
Sequence6: Sequence> (_ sequence2: Sequence2, _ sequence3: Sequence3, _ sequence4: Sequence4,
_ sequence5: Sequence5, _ sequence6: Sequence6) -> Product6Sequence<Self, Sequence2, Sequence3, Sequence4,
Sequence5, Sequence6> {
return Product6Sequence(self, sequence2, sequence3, sequence4, sequence5, sequence6)
}
}
这个以及其他类似的 Sequence
扩展可以在我创建的名为 SequenceExtensions.