使用函数时编译时间长 (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 Sequences 那么编译会冻结我的机器。

编辑:从那以后我发现这些类型的 Sequences 默认情况下应该是惰性的。使用与 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.

的库中找到