Code Monkey home page Code Monkey logo

swiftz's Introduction

Build Status

Swiftz

Swiftz is a Swift library for functional programming.

It defines functional data structures, functions, idioms, and extensions that augment the Swift standard library.

For a small, simpler way to introduce functional primitives into any codebase, see Swiftx.

Setup

To add Swiftz to your application:

Using Carthage

  • Add Swiftz to your Cartfile
  • Run carthage update
  • Drag the relevant copy of Swiftz into your project.
  • Expand the Link Binary With Libraries phase
  • Click the + and add Swiftz
  • Click the + at the top left corner to add a Copy Files build phase
  • Set the directory to Frameworks
  • Click the + and add Swiftz

Using Git Submodules

  • Clone Swiftz as a submodule into the directory of your choice
  • Run git submodule init -i --recursive
  • Drag Swiftz.xcodeproj or Swiftz-iOS.xcodeproj into your project tree as a subproject
  • Under your project's Build Phases, expand Target Dependencies
  • Click the + and add Swiftz
  • Expand the Link Binary With Libraries phase
  • Click the + and add Swiftz
  • Click the + at the top left corner to add a Copy Files build phase
  • Set the directory to Frameworks
  • Click the + and add Swiftz

Introduction

Swiftz draws inspiration from a number of functional libraries and languages. Chief among them are Scalaz, Prelude/Base, SML Basis, and the OCaml Standard Library. Elements of the library rely on their combinatorial semantics to allow declarative ideas to be expressed more clearly in Swift.

Swiftz is a proper superset of Swiftx that implements higher-level data types like Lenses, Zippers, HLists, and a number of typeclasses integral to programming with the maximum amount of support from the type system.

To illustrate use of these abstractions, take these few examples:

Lists

import struct Swiftz.List

/// Cycles a finite list of numbers into an infinite list.
let finite : List<UInt> = [1, 2, 3, 4, 5]
let infiniteCycle = finite.cycle()

/// Lists also support the standard map, filter, and reduce operators.
let l : List<Int> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

let twoToEleven = l.map(+1) // [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
let even = l.filter((==0)  (%2)) // [2, 4, 6, 8, 10]
let sum = l.reduce(curry(+), initial: 0) // 55

/// Plus a few more.
let partialSums = l.scanl(curry(+), initial: 0) // [0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
let firstHalf = l.take(5) // [1, 2, 3, 4, 5]
let lastHalf = l.drop(5) // [6, 7, 8, 9, 10]

JSON

import protocol Swiftz.JSONDecode
import struct Swiftz.JSONKeypath
    
public class User : JSONDecodable {
    typealias J = User
    let name : String
    let age : Int
    let tweets : [String]
    let attr : String
    
    public init(_ n : String, _ a : Int, _ t : [String], _ r : String) {
        name = n
        age = a
        tweets = t
        attr = r
    }
    
    // JSON
    public class func create(x : String) -> Int -> ([String] -> String -> User) {
        return { y in { z in { User(x, y, z, $0) } } }
    }
    
    public class func fromJSON(x : JSONValue) -> User? {
        return User.create
			<^> x <? "name" 
			<*> x <? "age"
			<*> x <? "tweets" 
			<*> x <? "attrs" <> "one" // A nested keypath
    }
    
    // lens example
    public class func luserName() -> Lens<User, User, String, String> {
        return Lens { user in IxStore(user.name) { User($0, user.age, user.tweets, user.attr) } }
    }
}

public func ==(lhs : User, rhs : User) -> Bool {
    return lhs.name == rhs.name && lhs.age == rhs.age && lhs.tweets == rhs.tweets && lhs.attr == rhs.attr
}

let userjs = "{\"name\": \"max\", \"age\": 10, \"tweets\": [\"hello\"], \"attrs\": {\"one\": \"1\"}}"

/// The JSON we've decoded works perfectly with the User structure we defined above.  In case it didn't,
/// the user would be nil.
let user : User? = JSONValue.decode(userjs) >>- User.fromJSON // .Some( User("max", 10, ["hello"], "1") )

Lenses

import struct Swiftz.Lens
import struct Swiftz.IxStore

/// A party has a host, who is a user.
final class Party {
    let host : User

    init(h : User) {
        host = h
    }

    class func lpartyHost() -> Lens<Party, Party, User, User> {
        let getter = { (party : Party) -> User in
            party.host
        }

        let setter = { (party : Party, host : User) -> Party in
            Party(h: host)
        }

        return Lens(get: getter, set: setter)
    }
}

/// A Lens for the User's name.
extension User {
    public class func luserName() -> Lens<User, User, String, String> {
        return Lens { user in IxStore(user.name) { User($0, user.age, user.tweets, user.attrs) } }
    }
}

/// Let's throw a party now.
let party = Party(h: User("max", 1, [], Dictionary()))

/// A lens for a party host's name.
let hostnameLens = Party.lpartyHost()  User.luserName()

/// Retrieve our gracious host's name.
let name = hostnameLens.get(party) // "max"

/// Our party seems to be lacking in proper nouns. 
let updatedParty = (Party.lpartyHost()  User.luserName()).set(party, "Max")
let properName = hostnameLens.get(updatedParty) // "Max"

Semigroups and Monoids

let xs = [1, 2, 0, 3, 4]

import protocol Swiftz.Semigroup
import func Swiftz.sconcat
import struct Swiftz.Min

/// The least element of a list can be had with the Min Semigroup.
let smallestElement = sconcat(Min(2), xs.map { Min($0) }).value() // 0

import protocol Swiftz.Monoid
import func Swiftz.mconcat
import struct Swiftz.Sum

/// Or the sum of a list with the Sum Monoid.
let sum = mconcat(xs.map { Sum($0) }).value() // 10

import struct Swiftz.Product

/// Or the product of a list with the Product Monoid.
let product = mconcat(xs.map { Product($0) }).value() // 0

Arrows

import struct Swiftz.Function
import struct Swiftz.Either

/// An Arrow is a function just like any other.  Only this time around we
/// can treat them like a full algebraic structure and introduce a number
/// of operators to augment them.
let comp = Function.arr(+3)  Function.arr(*6)  Function.arr(/2)
let both = comp.apply(10) // 33

/// An Arrow that runs both operations on its input and combines both
/// results into a tuple.
let add5AndMultiply2 = Function.arr(+5) &&& Function.arr(*2)
let both = add5AndMultiply2.apply(10) // (15, 20)

/// Produces an Arrow that chooses a particular function to apply
/// when presented with the side of an Either.
let divideLeftMultiplyRight = Function.arr(/2) ||| Function.arr(*2)
let left = divideLeftMultiplyRight.apply(Either.left(4)) // 2
let right = divideLeftMultiplyRight.apply(Either.right(7)) // 14

Concurrency

import class Swiftz.Chan

/// A Channel is an unbounded FIFO stream of values with special semantics
/// for reads and writes.
let chan : Chan<Int> = Chan()

/// All writes to the Channel always succeed.  The Channel now contains `1`.
chan.write(1) // happens immediately

/// Reads to non-empty Channels occur immediately.  The Channel is now empty.
let x1 = chan.read()

/// But if we read from an empty Channel the read blocks until we write to the Channel again.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * Double(NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
    chan.write(2) // Causes the read to suceed and unblocks the reading thread.
})

let x2 = chan.read() // Blocks until the dispatch block is executed and the Channel becomes non-empty.

Operators

Swiftz introduces the following operators at global scope

Operator Name Type
compose • <A, B, C>(B -> C, A -> B) -> A -> C
`< ` apply
` >` thrush
<- extract <- <A>(M<A>, A) -> Void
union ∪ <A>(Set<A>, Set<A>) -> Set<A>
intersect ∩ <A>(Set<A>, Set<A>) -> Set<A>
!! from !! <A, ..., F>(NSErrorPointer, A, ..., F) -> Result<F>
<> op <> <A : Monoid>(A, A) -> A
<? retrieve <? <A : JSONDecodable>(JSONValue, JSONKeypath) -> A?
<! force retrieve <! <A : JSONDecodable>(JSONValue, JSONKeypath) -> A
<^> fmap <^> <A, B>(A -> B, a: F<A>) -> F<B>
<^^> imap <^^> <I, J, A>(I -> J, F<I, A>) -> F<J, A>
<!> contramap <^> <I, J, A>(J -> I, F<I, A>) -> F<J, A>
<*> apply <*> <A, B>(F<A -> B>, F<A>) -> F<B>
>>- bind >>- <A, B>(F<A>, A -> F<B>) -> F<B>
->> extend ->> <A, B>(F<A>, F<A> -> B) -> F<B>
<<< r-t-l compose >>> <C, A, B, C>(C<A, B>, C<B, C>) -> C<A, C>
>>> l-t-r compose <<< <C, A, B, C>(C<B, C>, C<A, B>) -> C<A, C>
&&& split &&& <A, B, C, D>(A<B, C>, A<B, D>) -> A<B, (C, D)>
*** fanout *** <A, B, C, D, E>(A<B, C>, A<D, E>) -> A<(B, D), (C, E)>
+++ splat +++ <A, B, C, D, E>(A<B, C>, A<D, E>) -> A<Either<D, B>, Either<C, E>>
`
<+> op <+> <A, B, C>(A<B, C>, A<B, C>) -> A<B, C>

System Requirements

Swiftz supports OS X 10.9+ and iOS 7.0+.

License

Swiftz is released under the BSD license.

swiftz's People

Contributors

codafi avatar mxswd avatar pthariensflame avatar tlewisii avatar joshaber avatar maxcan avatar cobbal avatar joshvera avatar hffmnn avatar brendonjustin avatar cartazio avatar dtchepak avatar josephlord avatar kasrak avatar ikesyo avatar michaelgwelch avatar mpurland avatar cheecheeo avatar iluuu1994 avatar sharplet avatar berkus avatar mbrandonw avatar eddmann avatar jckarter avatar jspahrsummers avatar lsavino avatar mgp avatar nikolaykasyanov avatar pyrtsa avatar rnapier avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.