diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f4c37c --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# Stream + +This is a Swift microframework providing a lazy `Stream` type with generic implementations of `==`/`!=` where `T`: `Equatable`. + +`Stream`s are lazily-populated as well as lazily-evaluated, making them convenient for procrastinating tasks you don’t want to do yet, like performing an expensive computation in successive stages. + +You can construct `Stream`s with `SequenceType`s, use them as `SequenceType`s, and `map` and `fold` to your heart’s content. + + +## Use + +Constructing a `Stream`: + +```swift +let empty: Stream = nil +let unary = Stream.pure(4) +let binary = Stream.cons(4, nil) +let fibonacci: Stream = fix { fib in // fix is from Prelude.framework + { x, y in Stream.cons(x + y, fib(y, x + y)) } +}(0, 1) +``` + +Note that `fibonacci` is infinite! Don’t worry about it, just don’t evaluate it all in one go (like with a `for` loop that never `break`s). + +It’s safe to extract values from any `Stream`, whether infinite or not: + +```swift +let (first, rest) = fibonacci.uncons +let first = fibonacci.first +let rest = fibonacci.rest +let isEmpty = fibonacci.isEmpty +``` + +Better yet, use `take` and `drop` to do the heavy lifting for you, or `map` to compute whatever you need to in a new infinite `Stream`: + +```swift +// Bad, infinite loops: +for each in fibonacci {} + +// Okay, stops: +for each in fibonacci { break } + +// Good, doesn’t compute anything til you iterate the result: +let firstFive = fibonacci.take(5) + +// Best, doesn’t compute anything til you iterate, and it’s infinite too: +let fibonacciSquares = fibonacci.map { x in x * x } +``` + +You can combine `Stream`s together by concatenating them using the `++` operator—even infinite ones: + +```swift +let aleph = fibonacci ++ fibonacci +``` + +This is more useful for prepending elements onto an infinite stream, though: + +```swift +let fibonacciSquaresForABit = firstFive.map { x in x * x } ++ fibonacci.drop(5) +``` + +Full API documentation is in the source. + + +## Integration + +1. Add this repository as a submodule and check out its dependencies, and/or [add it to your Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile) if you’re using [carthage](https://github.com/Carthage/Carthage/) to manage your dependencies. +2. Drag `Stream.xcodeproj` into your project or workspace, and do the same with its dependencies (i.e. the other `.xcodeproj` files included in `Stream.xcworkspace`). NB: `Stream.xcworkspace` is for standalone development of Stream, while `Stream.xcodeproj` is for targets using Stream as a dependency. +3. Link your target against `Stream.framework` and each of the dependency frameworks. +4. Application targets should ensure that the framework gets copied into their application bundle. (Framework targets should instead require the application linking them to include Stream and its dependencies.) diff --git a/StreamTests/StreamTests.swift b/StreamTests/StreamTests.swift index d46fe08..1a41e5f 100644 --- a/StreamTests/StreamTests.swift +++ b/StreamTests/StreamTests.swift @@ -151,6 +151,11 @@ class StreamTests: XCTestCase { XCTAssertEqual(reduce(concatenated, "0", { $0 + toString($1) }), "0123456") } + func testConcatenationOfInfiniteStreams() { + let concatenated = fibonacci ++ fibonacci + XCTAssertEqual(concatenated.first ?? -1, 1) + } + func testFoldLeft() { XCTAssertEqual(Stream([1, 2, 3]).foldLeft("0", { $0 + toString($1) }), "0123") }