You could replace `forEach` with a supped up `map` that also allowed `break` 
and `continue`. The following library function gives `continue` and `break` and 
also combines `repeat`, `times`, `forEach`, `filter`, `flatMap`, and `map` into 
one:

public final class MapController<E, R> {
    var results = [R]()
    
    var isContinuing = true
    
    init<C: CollectionType where C.Generator.Element == E>(_ collection: C, 
sizeEstimate: Int = 0, @noescape mapper: (controller: MapController<E, R>, 
element: E) throws -> R?) rethrows {
        results.reserveCapacity(sizeEstimate)
        for var generator = collection.generate(), element = generator.next(); 
element != nil && isContinuing; element = generator.next() {
            let result = try mapper(controller: self, element: element!)
            if let actualResult = result {
                results.append(actualResult)
            }
        }
    }
}

extension CollectionType {
    /// Controllable `map`, additional controls beyond simple `map` are:
    ///
    ///   1. Continue without returning a result (`return nil`)
    ///   2. Return multiple results (`control.results += [...]` then `return 
nil`)
    ///   3. Break (`control.isContinuing = false` then `return nil`)
    ///
    /// These additional controls allow this `map` to function like `repeat`, 
`times`, `forEach`, `filter`, `flatMap`, and `map` combined into one as well as 
providing an early termination (break).
    @warn_unused_result func map<R>(sizeEstimate sizeEstimate: Int = 0, 
@noescape mapper: (controller: MapController<Self.Generator.Element, R>, 
element: Self.Generator.Element) throws -> R?) rethrows -> [R] {
        return try MapController(self, sizeEstimate: sizeEstimate, mapper: 
mapper).results
    }
}

// Demonstration of full functionality including continue, break, and multiple 
returns
var result = (0 ..< 5).map { (control, index) -> Int? in
    switch index {
    case 1:
        return nil // Continue - skip 1 (`filter`)
    case 2:
        control.results.append(2) // Yield two results - this one and the 
'return’ yield (`flatMap`)
    case 3:
        control.isContinuing = false // Break after next yield - which could be 
`return nil` if there are no more results
    default:
        break
    }
    return index // Yield next result - except for case 1 all the above yield 
`index`
}
print(result) // prints `[0, 2, 2, 3]` note missing "1", double "2", and last 
is "3"

// Demonstration of `repeat`/`forEach`/`times` like usage - note `(_, _) -> 
Void?`
result = [Int]()
(0 ..< 3).map { (_, _) -> Void? in
    result.append(1) // Do whatever - in this case append to a global
    return nil // Don't yield any results
}
print(result) // prints `[1, 1, 1]`

Would this be a superior alternative to both `forEach` and `times` in the 
library and `repeat` as a language feature?

Sent from my iPad
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to