Uploaded image for project: 'Swift'
  1. Swift
  2. SR-2065

Quell forloopian distemper by extending sequence to include a terminating condition

    XMLWordPrintable

    Details

    • Type: Improvement
    • Status: Open
    • Priority: Medium
    • Resolution: Unresolved
    • Component/s: Standard Library
    • Labels:
      None

      Description

      /// Returns a sequence formed from `first` and repeated lazy applications of
      /// `next` until a user-supplied `while` test fails.
      ///
      /// The first element in the sequence is always `first`, and each successive
      /// element is the result of invoking `next` with the previous element. The
      /// sequence ends when `next` returns `nil` or when the user-supplied test
      /// returns false. If `next` never returns `nil` and the test never fails,
      /// the sequence is infinite.
      ///
      /// This function can be used to replace many cases that were previously handled
      /// using C-style `for` loops and includes a stopping test without requiring
      /// a secondary prefix function.
      ///
      /// Example:
      ///
      /// The following Swift 2.2-and-earlier C-style loop prints
      /// out numbers from 0 to 49:
      ///
      ///    for var i = 0, j = 100; i < j; i++, j-- {
      ///        print(i)
      ///     }
      ///
      /// This can be refactored in Swift using the same first, next, and test
      /// components:
      ///
      ///    for (i, j) in sequence(
      ///        first: (i: 0, j: 100),
      ///        next: { ($0.i + 1, $0.j - 1) },
      ///        while: { $0.i < $0.j })
      ///    {
      ///        print (i) // count to 49
      ///    }
      ///
      ///
      /// - Parameter first: The first element to be returned from the sequence.
      /// - Parameter next: A closure that accepts the previous sequence element and
      ///   returns the next element.
      /// - Parameter while: A closure that tests the next value and returns true or
      ///   false, forcing the sequence to end
      /// - Returns: A sequence that starts with `first` and continues with every
      ///   value returned by passing the previous element to `next` until test(value)
      ///   fails
      ///
      /// - SeeAlso: `sequence(state:next:)`, `sequence(first:next:)`
      public func sequence<T>(first: T, next: (T) -> T?, while test: (T) -> Bool) -> UnfoldSequence<T, (T?, Bool)> {
        return sequence(state: (first, true), next: { (state: inout (T?, Bool)) -> T? in
          switch state {
            case (let value?, true):
              state.1 = false
              if !test(value) {
                state.0 = nil; return nil
              }
              return value
            case (let value?, false):
              let nextValue = next(value)
              if 
                let nextValue = nextValue, 
                !test(nextValue) {
                  state.0 = nil; return nil
              }
              state.0 = nextValue
              return nextValue
            default:
              return nil
          }
        })
      }

        Attachments

          Activity

            People

            Assignee:
            Unassigned
            Reporter:
            erica erica sadun
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated: