Last active
April 7, 2016 11:19
-
-
Save beccadax/b24dd89a770d9fe376984498d3185187 to your computer and use it in GitHub Desktop.
Suggested replacement for C-style for.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Sequence of 1, 2, 4 ... 64 | |
induce(from: 1, to: 128, by: { $0 * 2 }) | |
induce(from: 1, to: 128, by: { $0 *= 2 }) | |
// Sequence of 1, 2, 4 ... 128 | |
induce(from: 1, through: 128, by: { $0 * 2 }) | |
induce(from: 1, through: 128, by: { $0 *= 2 }) | |
// Sequence of 1, 2, 4 ... with arbitrary, calculated bound | |
import Darwin | |
induce(from: 1, while: { sqrt(Double($0)) < 20 }, by: { $0 * 2 }) | |
induce(from: 1, while: { sqrt(Double($0)) < 20 }, by: { $0 *= 2 }) | |
// Sequence of two values in a tuple: | |
induce(from: (1, 10), while: { $0.0 < 128 }, by: { $0.0 *= 2; $0.1 *= 2 }) | |
// C-style for loop: | |
for var i = 1; i < 128; i *= 2 { print(i) } | |
// Literal converted form: | |
for i in induce(from: 1, while: { $0 < 128 }, by: { $0 *= 2 }) { print(i) } | |
// Idomatic converted form: | |
for i in induce(from: 1, to: 128, by: { $0 * 2 }) { print(i) } | |
// It would be really nice if you could say something like one of these: | |
// for i in induce(from: 1, to: 128, by: * 2) { print(i) } | |
// for i in induce(from: 1, to: 128, by: _ * 2) { print(i) } | |
// for i in induce(from: 1, to: 128, by: i * 2) { print(i) } | |
// But that kind of thing has been rejected before. Sigh... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file is not optimized or stdlib-ready. It's merely meant to demonstrate the logic the various | |
// `induce` functions are intended to implement. | |
/// Returns a lazy sequence which begins with the `start` element, then derives subsequent elements | |
/// by repeatedly calling the `next` function with the previous element to calculate the next element. | |
/// Continues as long as the `inBounds` function continues to return `true` for each element. | |
/// | |
/// If `inBounds` is omitted, the sequence created by this function is infinite. | |
public func induce<Element>(from start: Element, while inBounds: Element -> Bool = { _ in true }, by next: Element -> Element) -> InductionSequence<Element> { | |
return induce(from: start, while: inBounds, by: formify(next)) | |
} | |
/// Returns a lazy sequence which begins with the `start` element, then derives subsequent elements | |
/// by repeatedly calling the `formNext` function to transform the previous element into the next one. | |
/// Continues as long as the `inBounds` function continues to return `true` for each element. | |
/// | |
/// If `inBounds` is omitted, the sequence created by this function is infinite. | |
public func induce<Element>(from start: Element, while inBounds: Element -> Bool = { _ in true }, by formNext: inout Element -> Void) -> InductionSequence<Element> { | |
return InductionSequence(start: start, inBounds: inBounds, formNext: formNext) | |
} | |
/// Returns a lazy sequence which begins with the `start` element, then derives subsequent elements | |
/// by repeatedly calling the `next` function with the previous element to calculate the next element. | |
/// Continues as long as the elements stay between `start` (inclusive) and `end` (exclusive). | |
func induce<Element: Comparable>(from start: Element, to end: Element, by next: Element -> Element) -> InductionSequence<Element> { | |
return induce(from: start, to: end, by: formify(next)) | |
} | |
/// Returns a lazy sequence which begins with the `start` element, then derives subsequent elements | |
/// by repeatedly calling the `formNext` function to transform the previous element into the next one. | |
/// Continues as long as the elements stay between `start` (inclusive) and `end` (exclusive). | |
func induce<Element: Comparable>(from start: Element, to end: Element, by formNext: inout Element -> Void) -> InductionSequence<Element> { | |
let inBounds = (start < end) ? { $0 < end } : { $0 > end } | |
return induce(from: start, while: inBounds, by: formNext) | |
} | |
/// Returns a lazy sequence which begins with the `start` element, then derives subsequent elements | |
/// by repeatedly calling the `next` function with the previous element to calculate the next element. | |
/// Continues as long as the elements stay between `start` (inclusive) and `end` (inclusive). | |
func induce<Element: Comparable>(from start: Element, through end: Element, by next: Element -> Element) -> InductionSequence<Element> { | |
return induce(from: start, through: end, by: formify(next)) | |
} | |
/// Returns a lazy sequence which begins with the `start` element, then derives subsequent elements | |
/// by repeatedly calling the `formNext` function to transform the previous element into the next one. | |
/// Continues as long as the elements stay between `start` (inclusive) and `end` (inclusive). | |
func induce<Element: Comparable>(from start: Element, through end: Element, by formNext: inout Element -> Void) -> InductionSequence<Element> { | |
let inBounds = (start < end) ? { $0 <= end } : { $0 >= end } | |
return induce(from: start, while: inBounds, by: formNext) | |
} | |
/// A lazy, possibly infinite sequence derived from a starting element and a function which calculates | |
/// the next value. | |
/// | |
/// -SeeAlso: `induce(from:to:by:)`, `induce(from:through:by:)`, `induce(from:while:by:)` | |
public struct InductionSequence<Element>: SequenceType { | |
let start: Element | |
let inBounds: Element -> Bool | |
let formNext: inout Element -> Void | |
public func generate() -> InductionGenerator<Element> { | |
return .init(current: start, inBounds: inBounds, formNext: formNext) | |
} | |
} | |
/// A lazy, possibly infinite generator associated with an `InductionSequence`. | |
public struct InductionGenerator<Element>: GeneratorType { | |
var current: Element | |
let inBounds: Element -> Bool | |
let formNext: inout Element -> Void | |
public mutating func next() -> Element? { | |
if !inBounds(current) { | |
return nil | |
} | |
defer { formNext(¤t) } | |
return current | |
} | |
} | |
/// Converts a functional-style operation into a mutating-style operation. | |
private func formify<T>(function: T -> T) -> (inout T) -> Void { | |
return { $0 = function($0) } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@brentdax Heh, likewise, I like the functionality of
induce
but not the name. You could even call ititerate
, and simply make thewhile:
-less overload work the way I suggested.xs.prefix {...}
or evenxs.while {...}
could work as well.