maartz/swiftpipeline
SwiftPipeline is a lightweight, functional-style library for Swift that brings the power of **threading macros** and **functional operators** inspired by languages like **Clojure** and **Haskell**. With clean and expressive operators, SwiftPipeline allows you to thread data throu
Features π―
Threading Operators
- Thread-first (
=>): Passes the value as the first argument to functions or uses KeyPaths for property extraction - Thread-last (
=>>): Passes the value as the last argument to functions - Thread-as (
~=>): Binds a value to a name for custom transformations
Functional Operators
- FlatMap (
<|): Applies functions to optional values or arrays - Applicative (
<*>): Applies wrapped functions to wrapped values - Kleisli composition (
>=>): Composes functions that return optionals - Alternative (
<|>): Provides fallback values for computations - Monadic bind (
>>-): Chains operations that produce optionals - Reverse bind (
-<<): Flipped version of monadic bind
Why SwiftPipeline? π€
Clean and Declarative Code
- Transform your Swift code into highly expressive and readable pipelines
- Chain operations in a natural, left-to-right flow
- Reduce nested function calls and temporary variables
- Make complex data transformations clear and maintainable
Rich Functional Programming Patterns
- Combines threading macros from Clojure with functional operators from Haskell
- Powerful composition with monadic, applicative, and alternative operators
- Strong type safety while maintaining functional programming elegance
- Makes optional handling and error propagation elegant
Lightweight and Swift-Native
- Zero external dependenciesβpure Swift implementation
- Minimal runtime overhead
- Small API surface with maximum expressiveness
- Seamlessly integrates with Swift's type system and standard library
Flexible and Extensible
- Works with any Swift type, including your custom types
- Combines beautifully with Swift's KeyPaths
- Easy to extend with your own operators
- Perfect for both small scripts and large applications
Battle-Tested Patterns
- Based on proven functional programming concepts
- Inspired by decades of FP best practices
- Makes complex operations predictable and safe
- Reduces cognitive load when dealing with complex transformations
Great for Teams
- Makes code intent clear and self-documenting
- Reduces merge conflicts by encouraging linear transformations
- Easy to learn, hard to misuse
- Consistent patterns across your codebase
Whether you're building data pipelines, handling optional chains, or just want cleaner code, SwiftPipeline provides the tools you need without the bloat.
Installation π₯
Add SwiftPipeline to your project using the Swift Package Manager:
- Open your project in Xcode
- Go to File > Add Packages
- Enter the following repository URL:
``plaintext https://github.com/Maartz/SwiftPipeline.git ``
- Select the latest version and add the package
Usage π
Basic Threading Operators
Thread-first (=>)
struct Person {
let name: String
let age: Int
}
let person = Person(name: "Alice", age: 30)
let result = person
=> \.name
=> { $0.uppercased() }
// Output: "ALICE"Thread-last (=>>)
let numbers = [1, 2, 3]
let result = numbers
=>> { $0.map { $0 + 1 } }
=>> { $0.filter { $0 % 2 != 0 } }
=>> { $0.reduce(0, +) }
// Output: 6Thread-as (~=>)
let total = 5
~=> { x in x + 10 }
=> { $0 * 2 }
// Output: 30Functional Operators
Map (<|)
// With optionals
let double: (Int) -> Int = { $0 * 2 }
let result = double <| Some(5) // Optional(10)
// With arrays
let numbers = [1, 2, 3]
let doubled = double <| numbers // [2, 4, 6]Applicative (<*>)
let maybeDouble: ((Int) -> Int)? = { $0 * 2 }
let result = maybeDouble <*> Some(5) // Optional(10)
// With arrays
let functions = [{ $0 * 2 }, { $0 + 3 }]
let values = [1, 2]
let results = functions <*> values // [2, 4, 4, 5]Alternative (<|>)
let parseNumber: (String) -> Int? = { Int($0) }
let result = parseNumber("invalid") <|> parseNumber("42") <|> Some(0)
// Falls back to valid parsing or defaultMonadic Bind (>>-) and Reverse Bind (-<<)
let parseId: (String) -> Int? = { Int($0) }
let findUser: (Int) -> User? = { id in
// Find user by id
id == 42 ? User(id: 42, name: "John") : nil
}
// Using >>-
let user1 = "42" >>- parseId >>- findUser
// Using -<<
let user2 = findUser -<< (parseId -<< "42")Complex Examples
Optional Chaining with Alternatives
struct User {
let id: Int
let email: String?
}
let validateEmail: (String) -> String? = { email in
email.contains("@") ? email : nil
}
let result = parseId -<< "42"
>>- findUser
>>- { user in user.email >>- validateEmail }
<|> Some("default@email.com")Applicative with Computations
let compute: (Int) -> (Int) -> Int? = { x in
{ y in (x + y) > 0 ? x + y : nil }
}
let result = (parseId -<< "5" >>- compute)
<*> Some(-3)
<|> Some(10)API Reference π
Operators
| Operator | Type | Description | Example Usage | |----------|------|-------------|---------------| | => | Threading | Thread-first | value => function | | =>> | Threading | Thread-last | value =>> function | | ~=> | Threading | Thread-as | value ~=> { $0 2 } | | <\| | Functional | Map | function <\| optional | | <> | Functional | Applicative | wrappedFn <*> wrappedValue | | >=> | Functional | Kleisli composition | f >=> g | | <\|> | Functional | Alternative | computation1 <\|> computation2 | | >>- | Functional | Monadic bind | value >>- function | | -<< | Functional | Reverse bind | function -<< value |
Contributing π€
We welcome contributions! Feel free to:
- Submit a bug report or feature request
- Fork the repository and open a pull request
License π
This project is licensed under the MIT License. See the LICENSE file for details.
Acknowledgements π
SwiftPipeline is inspired by the threading macros of Clojure and functional operators from Haskell, aiming to bring similar functionality to the Swift ecosystem.
Enjoy using SwiftPipeline! π
Package Metadata
Repository: maartz/swiftpipeline
Default branch: main
README: README.md