Skip to content

One reduce overload to match reductions is missing. #241

Open
@JessyCatterwaul

Description

@JessyCatterwaul

Four of the six reductions overloads correspond to a reduce overload from the standard library.

The missing overload should return nil, for empty sequences.

@Test func reduce() {
  let sequence = [1, 2, 3, 4]
  #expect(sequence.reductions(+) == [1, 3, 6, 10])
  #expect(sequence.reduce(+) == 10)

  #expect(EmptyCollection<Int>().reductions(+) == [])
  #expect(EmptyCollection<Int>().reduce(+) == nil)
}

Here's an implementation without typed throws:

public extension Sequence
  @inlinable func reduce(
    _ nextPartialResult: (Element, Element) throws -> Element
  ) rethrows -> Element? {
    var iterator = makeIterator()
    return try iterator.next().map { first in
      try IteratorSequence(iterator).reduce(first, nextPartialResult)
    }
  }
}

Typed throws should be used, however.

  @inlinable func reduce<Error>(
    _ nextPartialResult: (Element, Element) throws(Error) -> Element
  ) throws(Error) -> Element? {
    var iterator = makeIterator()
    return try iterator.next().map { first throws(Error) in
      try forceCastError(
        to: Error.self,
        IteratorSequence(iterator).reduce(first, nextPartialResult)
      )
    }
  }
/// A mechanism to interface between untyped and typed errors.
///
/// When you know for certain that a value may only throw one type of error,
/// but that guarantee is not (or, due to compiler bugs, cannot be) represented in the type system,
/// you can use this to "convert" it to "typed throws".
/// - Parameters:
///   - errorType: The error type known for certain to be thrown by `value`.
///   - value: A value that might throw an `Error`.
/// - Important: A crash will occur if `value` throws any type but `Error`.
/// - Bug: [`errorType` must be explicitly provided](https://github.com/swiftlang/swift/issues/75674).
public func forceCastError<Value, Error>(
  to errorType: Error.Type = Error.self,
  _ value: @autoclosure () throws -> Value
) throws(Error) -> Value {
  do { return try value() }
  catch { throw error as! Error }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions