apple / apple/swift-algorithms

One `reduce` overload to match `reductions` is missing.

Open
#241 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Swift
Stars
6.3k
Forks
483
PR merge metrics
No merged PRs in 30d

Description

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

1.
* [reduce(_:_:)](https://developer.apple.com/documentation/swift/sequence/reduce(_:_:))
* [reductions(_:_:)](https://swiftpackageindex.com/apple/swift-algorithms/1.2.0/documentation/algorithms/swift/sequence/reductions(_:_:))
* [lazy version](https://swiftpackageindex.com/apple/swift-algorithms/1.2.0/documentation/algorithms/swift/lazysequenceprotocol/reductions(_:_:))

2.
* [reduce(into:_:)](https://developer.apple.com/documentation/swift/sequence/reduce(into:_:))
* [reductions(into:_:)](https://swiftpackageindex.com/apple/swift-algorithms/1.2.0/documentation/algorithms/swift/sequence/reductions(into:_:))
* [lazy version](https://swiftpackageindex.com/apple/swift-algorithms/1.2.0/documentation/algorithms/swift/lazysequenceprotocol/reductions(into:_:))

3.
* This `reduce` overload is missing.
* [reductions(_:)](https://swiftpackageindex.com/apple/swift-algorithms/1.2.0/documentation/algorithms/swift/sequence/reductions(_:))
* [lazy version](https://swiftpackageindex.com/apple/swift-algorithms/1.2.0/documentation/algorithms/swift/lazysequenceprotocol/reductions(_:))

The missing overload should return `nil`, for empty sequences.

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

#expect(EmptyCollection().reductions(+) == [])
#expect(EmptyCollection().reduce(+) == nil)
}
```

Here's an implementation without typed throws:

```swift
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.

```swift
@inlinable func reduce(
_ 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)
)
}
}
```

```swift
/// 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(
to errorType: Error.Type = Error.self,
_ value: @autoclosure () throws -> Value
) throws(Error) -> Value {
do { return try value() }
catch { throw error as! Error }
}
```

Contributor guide

Open the contributing guide

Research direction

Start by locating the existing Sequence.reductions overloads and the related reduce entry points, then compare their signatures and error-handling conventions. Add coverage to the shown reduce test for nonempty and empty sequences, including typed throws; done means the missing overload matches the reductions API and returns nil for an empty sequence.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
tooling
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.