Skip to content

Commit d1c87f3

Browse files
authored
Merge pull request #24270 from natecook1000/nc_lazyscan_fix
2 parents ad4d623 + f6547cc commit d1c87f3

File tree

1 file changed

+91
-91
lines changed

1 file changed

+91
-91
lines changed

stdlib/public/core/LazySequence.swift

Lines changed: 91 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -10,124 +10,124 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
/// A sequence on which normally-eager operations such as `map` and
14-
/// `filter` are implemented lazily.
13+
/// A sequence on which normally-eager sequence operations are implemented
14+
/// lazily.
1515
///
1616
/// Lazy sequences can be used to avoid needless storage allocation
1717
/// and computation, because they use an underlying sequence for
18-
/// storage and compute their elements on demand. For example,
18+
/// storage and compute their elements on demand. For example, `doubled` in
19+
/// this code sample is a sequence containing the values `2`, `4`, and `6`.
1920
///
20-
/// [1, 2, 3].lazy.map { $0 * 2 }
21+
/// let doubled = [1, 2, 3].lazy.map { $0 * 2 }
2122
///
22-
/// is a sequence containing { `2`, `4`, `6` }. Each time an element
23-
/// of the lazy sequence is accessed, an element of the underlying
24-
/// array is accessed and transformed by the closure.
23+
/// Each time an element of the lazy sequence `doubled` is accessed, the
24+
/// closure accesses and transforms an element of the underlying array.
2525
///
26-
/// Sequence operations taking closure arguments, such as `map` and
27-
/// `filter`, are normally eager: they use the closure immediately and
28-
/// return a new array. Using the `lazy` property gives the standard
26+
/// Sequence operations that take closure arguments, such as `map(_:)` and
27+
/// `filter(_:)`, are normally eager: They use the closure immediately and
28+
/// return a new array. When you use the `lazy` property, you give the standard
2929
/// library explicit permission to store the closure and the sequence
3030
/// in the result, and defer computation until it is needed.
3131
///
32-
/// To add new lazy sequence operations, extend this protocol with
33-
/// methods that return lazy wrappers that are themselves
34-
/// `LazySequenceProtocol`s. For example, given an eager `scan`
35-
/// method defined as follows
32+
/// ## Adding New Lazy Operations
33+
///
34+
/// To add a new lazy sequence operation, extend this protocol with
35+
/// a method that returns a lazy wrapper that itself conforms to
36+
/// `LazySequenceProtocol`. For example, an eager `scan(_:_:)`
37+
/// method is defined as follows:
3638
///
3739
/// extension Sequence {
38-
/// /// Returns an array containing the results of
39-
/// ///
40-
/// /// p.reduce(initial, nextPartialResult)
41-
/// ///
42-
/// /// for each prefix `p` of `self`, in order from shortest to
43-
/// /// longest. For example:
44-
/// ///
45-
/// /// (1..<6).scan(0, +) // [0, 1, 3, 6, 10, 15]
46-
/// ///
47-
/// /// - Complexity: O(n)
48-
/// func scan<ResultElement>(
49-
/// _ initial: ResultElement,
50-
/// _ nextPartialResult: (ResultElement, Element) -> ResultElement
51-
/// ) -> [ResultElement] {
52-
/// var result = [initial]
53-
/// for x in self {
54-
/// result.append(nextPartialResult(result.last!, x))
40+
/// /// Returns an array containing the results of
41+
/// ///
42+
/// /// p.reduce(initial, nextPartialResult)
43+
/// ///
44+
/// /// for each prefix `p` of `self`, in order from shortest to
45+
/// /// longest. For example:
46+
/// ///
47+
/// /// (1..<6).scan(0, +) // [0, 1, 3, 6, 10, 15]
48+
/// ///
49+
/// /// - Complexity: O(n)
50+
/// func scan<Result>(
51+
/// _ initial: Result,
52+
/// _ nextPartialResult: (Result, Element) -> Result
53+
/// ) -> [Result] {
54+
/// var result = [initial]
55+
/// for x in self {
56+
/// result.append(nextPartialResult(result.last!, x))
57+
/// }
58+
/// return result
5559
/// }
56-
/// return result
57-
/// }
5860
/// }
5961
///
60-
/// we can build a sequence that lazily computes the elements in the
61-
/// result of `scan`:
62+
/// You can build a sequence type that lazily computes the elements in the
63+
/// result of a scan:
6264
///
63-
/// struct LazyScanIterator<Base: IteratorProtocol, ResultElement>
64-
/// : IteratorProtocol {
65-
/// mutating func next() -> ResultElement? {
66-
/// return nextElement.map { result in
67-
/// nextElement = base.next().map { nextPartialResult(result, $0) }
68-
/// return result
69-
/// }
70-
/// }
71-
/// var nextElement: ResultElement? // The next result of next().
72-
/// var base: Base // The underlying iterator.
73-
/// let nextPartialResult: (ResultElement, Base.Element) -> ResultElement
74-
/// }
75-
///
76-
/// struct LazyScanSequence<Base: Sequence, ResultElement>
77-
/// : LazySequenceProtocol // Chained operations on self are lazy, too
65+
/// struct LazyScanSequence<Base: Sequence, Result>
66+
/// : LazySequenceProtocol
7867
/// {
79-
/// func makeIterator() -> LazyScanIterator<Base.Iterator, ResultElement> {
80-
/// return LazyScanIterator(
81-
/// nextElement: initial, base: base.makeIterator(),
82-
/// nextPartialResult: nextPartialResult)
83-
/// }
84-
/// let initial: ResultElement
85-
/// let base: Base
86-
/// let nextPartialResult:
87-
/// (ResultElement, Base.Element) -> ResultElement
68+
/// let initial: Result
69+
/// let base: Base
70+
/// let nextPartialResult:
71+
/// (Result, Base.Element) -> Result
72+
///
73+
/// struct Iterator: IteratorProtocol {
74+
/// var base: Base.Iterator
75+
/// var nextElement: Result?
76+
/// let nextPartialResult:
77+
/// (Result, Base.Element) -> Result
78+
///
79+
/// mutating func next() -> Result? {
80+
/// return nextElement.map { result in
81+
/// nextElement = base.next().map {
82+
/// nextPartialResult(result, $0)
83+
/// }
84+
/// return result
85+
/// }
86+
/// }
87+
/// }
88+
///
89+
/// func makeIterator() -> Iterator {
90+
/// return Iterator(
91+
/// base: base.makeIterator(),
92+
/// nextElement: initial as Result?,
93+
/// nextPartialResult: nextPartialResult)
94+
/// }
8895
/// }
8996
///
90-
/// and finally, we can give all lazy sequences a lazy `scan` method:
97+
/// Finally, you can give all lazy sequences a lazy `scan(_:_:)` method:
9198
///
9299
/// extension LazySequenceProtocol {
93-
/// /// Returns a sequence containing the results of
94-
/// ///
95-
/// /// p.reduce(initial, nextPartialResult)
96-
/// ///
97-
/// /// for each prefix `p` of `self`, in order from shortest to
98-
/// /// longest. For example:
99-
/// ///
100-
/// /// Array((1..<6).lazy.scan(0, +)) // [0, 1, 3, 6, 10, 15]
101-
/// ///
102-
/// /// - Complexity: O(1)
103-
/// func scan<ResultElement>(
104-
/// _ initial: ResultElement,
105-
/// _ nextPartialResult: @escaping (ResultElement, Element) -> ResultElement
106-
/// ) -> LazyScanSequence<Self, ResultElement> {
107-
/// return LazyScanSequence(
108-
/// initial: initial, base: self, nextPartialResult: nextPartialResult)
109-
/// }
100+
/// func scan<Result>(
101+
/// _ initial: Result,
102+
/// _ nextPartialResult: @escaping (Result, Element) -> Result
103+
/// ) -> LazyScanSequence<Self, Result> {
104+
/// return LazyScanSequence(
105+
/// initial: initial, base: self, nextPartialResult: nextPartialResult)
106+
/// }
110107
/// }
111108
///
112-
/// - See also: `LazySequence`
109+
/// With this type and extension method, you can call `.lazy.scan(_:_:)` on any
110+
/// sequence to create a lazily computed scan. The resulting `LazyScanSequence`
111+
/// is itself lazy, too, so further sequence operations also defer computation.
113112
///
114-
/// - Note: The explicit permission to implement further operations
115-
/// lazily applies only in contexts where the sequence is statically
116-
/// known to conform to `LazySequenceProtocol`. Thus, side-effects such
117-
/// as the accumulation of `result` below are never unexpectedly
118-
/// dropped or deferred:
113+
/// The explicit permission to implement operations lazily applies
114+
/// only in contexts where the sequence is statically known to conform to
115+
/// `LazySequenceProtocol`. In the following example, because the extension
116+
/// applies only to `Sequence`, side-effects such as the accumulation of
117+
/// `result` are never unexpectedly dropped or deferred:
119118
///
120-
/// extension Sequence where Element == Int {
119+
/// extension Sequence where Element == Int {
121120
/// func sum() -> Int {
122-
/// var result = 0
123-
/// _ = self.map { result += $0 }
124-
/// return result
121+
/// var result = 0
122+
/// _ = self.map { result += $0 }
123+
/// return result
125124
/// }
126-
/// }
125+
/// }
127126
///
128-
/// [We don't recommend that you use `map` this way, because it
129-
/// creates and discards an array. `sum` would be better implemented
130-
/// using `reduce`].
127+
/// Don't actually use `map` for this purpose, however, because it creates
128+
/// and discards the resulting array. Instead, use `reduce` for summing
129+
/// operations, or `forEach` or a `for`-`in` loop for operations with side
130+
/// effects.
131131
public protocol LazySequenceProtocol: Sequence {
132132
/// A `Sequence` that can contain the same elements as this one,
133133
/// possibly with a simpler type.

0 commit comments

Comments
 (0)