This is a Swift framework providing a single collection interface, ReducibleType, suitable for representing the traversal of collections.
- Simplicity: one protocol,
ReducibleType, provides both enumeration and iteration. - Ease of use: enumerate with
reduce& iterate withStream. - Interoperability:
Streammakes a reducible fromSequenceType;sequence()supportsfor…in(and other clients ofSequenceType) with anyReducibleType. - Ease of adoption:
Stream&sequencesupport anySequenceTypeprovider or client;ReducibleTypeis similar to recursivereduce. - Consistency:
Streamis pure; retrieving the current element does not advance/mutate the stream; memoizes, avoiding repeated effects in impure producers. - Scope:
Streamevaluates lazily;reducecan be halted early; supports unbounded collections.
Swift’s SequenceType & GeneratorType interfaces support sequential traversal. However, they have several key drawbacks:
-
Fragility: requires mutable state; no access to the current element without mutating.
-
Difficulty of adoption:
SequenceTypecan be hard to implement; requirement to mutate makes debugging harder. -
Difficulty of use: advancing is subtle; correct backtracking requires (essentially)
Stream; no access to the current element without mutating. -
Complexity: ad hoc constraints which the compiler cannot enforce; constraints may differ between implementations; copies of generators are legal but should not be advanced separately; untenable promotion to even more complex
CollectionTypeinstead; per the comments:Any code that uses multiple generators (or
for…inloops) over a single sequence should have static knowledge that the specific sequence is multi-pass, either because its concrete type is known or because it is constrained toCollectionType. Also, the generators must be obtained by distinct calls to the sequence'sgenerate()method, rather than by copying. -
Inefficiency: Iteration (sequential access by client code calling into API) is generally less efficient than enumeration (sequential access by API calling into client code).
In contrast, Traversal’s ReducibleType interface does not depend on mutable state, enabling pure implementations, and provides a consistent, reliable basis for both enumeration and iteration at the caller’s discretion, with only a single method to implement.
- Check out this repository on your Mac:
git clone https://github.com/robrix/Traversal.git-
Check out its dependencies:
git submodule update --init --recursive
-
Open
Traversal.xcworkspace. -
Build the
Traversaltarget.
- Add this repository as a submodule and check out its dependencies, and/or add it to your Cartfile if you’re using carthage to manage your dependencies.
- Drag
Traversal.xcodeprojinto your project or workspace, and do the same with its dependencies (i.e. the other.xcodeprojfiles included inTraversal.xcworkspace). NB:Traversal.xcworkspaceis for standalone development of Traversal, whileTraversal.xcodeprojis for targets using Traversal as a dependency. - Link your target against
Traversal.frameworkand each of the dependency frameworks. - Application targets should ensure that the framework gets copied into their application bundle. (Framework targets should instead require the application linking them to include Traversal and its dependencies.)