Swiftz is a Swift library for functional programming.
It defines purely functional data structures and functions.
Data abstractions:
let xs: [Int8] = [1, 2, 0, 3, 4]
// we can use the Min semigroup to find the minimal element in xs
sconcat(Min(), 2, xs) // 0
// we can use the Sum monoid to find the sum of xs
mconcat(Sum<Int8, NInt8>(i: { return nint8 }), xs) // 10
Either and Result:
// Result represents something that could work or be an NSError.
// Say we have 2 functions, the first fetches from a web services,
// the second decodes the string into a User.
// Both *could* fail with an NSError, so we use a Result<A>.
func getWeb() -> Result<String> {
var e: NSError?
let str = doStuff("foo", e)
return Result(e, str)
}
func decodeWeb(str: String) -> Result<User> {
var e: NSError?
let user = decode(str, e)
return Result(e, user)
}
// We can compose these two functions with the `>>-` function.
let getUser: Result<User> = getWeb() >>- decodeWeb
switch (getUser) {
case let .Error(e): println("NSError: \(e)")
case let .Value(user): println(user.name)
}
// If we use getUser and getWeb fails, the NSError will be from doStuff.
// If decodeWeb fails, then it will be an NSError from decode.
// If both steps work, then it will be a User!
JSON:
let js: NSData = ("[1,\"foo\"]").dataUsingEncoding(NSUTF8StringEncoding,
allowLossyConversion: false)
let lhs: JSValue = JSValue.decode(js)
let rhs: JSValue = .JSArray([.JSNumber(1), .JSString("foo")])
XCTAssert(lhs == rhs)
XCTAssert(rhs.encode() == js)
// The User class blob/fc9fead44/swiftzTests/swiftzTests.swift#L14-L48
// implements JSONDecode, so we can decode JSON into it and get a `User?`
let userjs: NSData = ("{\"name\": \"max\", \"age\": 10, \"tweets\":
[\"hello\"], \"attrs\": {\"one\": \"1\"}}")
.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
let user: User? = JSValue.decode(userjs) >>- User.fromJSON
XCTAssert(user! == User("max", 10, ["hello"], ["one": "1"]))
Concurrency:
// we can delay computations with futures
let x: Future<Int> = Future(exec: gcdExecutionContext, {
sleep(1)
return 4
})
x.result() == x.result() // true, returns in 1 second
// Channels
let chan: Chan<Int> = Chan()
chan.write(1)
chan.write(2) // this could happen asynchronously
let x1 = chan.read()
let x2 = chan.read()
println((x1, x2)) // 1, 2
// we can map and flatMap over futures
x.map({ $0.description }).result() // "4", returns instantly
x.flatMap({ (x: Int) -> Future<Int> in
return Future(exec: gcdExecutionContext, { sleep(1); return x + 1 })
}).result() // sleeps another second, then returns 5
Swiftz Core only contains interfaces to concepts and implementations for data abstractions from the standard library.
Operator | Name | Type |
---|---|---|
pure |
pure | pure<A>(a: A) -> F<A> |
<^> |
fmap | <^><A, B>(f: A -> B, a: F<A>) -> F<B> |
<^^> |
imap | <^><I, J, A>(f: I -> J, f: F<I, A>) -> F<J, A> |
<!> |
contramap | <^><I, J, A>(f: J -> I, f: F<I, A>) -> F<J, A> |
<*> |
apply | <*><A, B>(f: F<A -> B>, a: F<A>) -> F<B> |
>>- |
bind | >>-<A, B>(a: F<A>, f: A -> F<B>) -> F<B> |
->> |
extend | ->><A, B>(a: F<A>, f: F<A> -> B) -> F<B> |
Types with instances of these operators:
Optional
Array
(non-determinism, cross product)Either
(right bias)Result
ImArray
Set
(except<*>
)
Note: these functions are not in any protocol. They are in global scope.
- Build the
.framework
- Copy it to your project
- Add a build phase to copy frameworks, and add that swiftz to the list
- Add
--deep
to "Other Code Signing Flags" - Check
Versions/A/Frameworks/
doesn't contain the Swift runtime (it will be duplicated with the App's copy of the runtime, causing a 4mb increase in file size)
Implemented:
Future<A>
,MVar<A>
andChan<A>
concurrency abstractionsJSON
types and encode / decode protocols- Lenses
Semigroup<A>
andMonoid<A>
with some instancesNum
protocolEither<L, R>
andResult<V>
maybe
forOptional<A>
,Dictionary
andArray
extensions- Immutable
Set<A: Hashable>
andImArray<A>