77
Swift Rocks 2! Alexander Voronov iOS Developer @ Stanfy

Swift Rocks #2: Going functional

Embed Size (px)

Citation preview

Swift Rocks 2!

Alexander Voronov iOS Developer @ Stanfy

SwiftGoing Functional

What is Functional Programming?

Functional Programming

Functional Programming

• Higher-order functions

Functional Programming

• Higher-order functions

• Immutable states & pure functions

Functional Programming

• Higher-order functions

• Immutable states & pure functions

• Modularity

Functional Programming

• Higher-order functions

• Immutable states & pure functions

• Modularity

• Types

Swift Power

Swift Power

Swift Power• First Class Functions

Swift Power• First Class Functions

• Currying

Swift Power• First Class Functions

• Currying

• Generics

Swift Power• First Class Functions

• Currying

• Generics

• Type Inference

Swift Power• First Class Functions

• Currying

• Generics

• Type Inference

• Enums

First Class Functionsfunc add(x: Int) -> Int -> Int { return { y in y + x } }

let addOne = add(1) addOne(2)

// 3

First Class Functionsfunc addTwo(x: Int) -> Int { return x + 2 }

(1...5).map(addTwo)

// [3, 4, 5, 6, 7]

Curryingfunc add(a: Int)(b: Int) -> Int { return a + b }

let addOne = add(1) let xs = 1...5 xs.map(addOne)

// [2, 3, 4, 5, 6]

Currying

func curry<A, B, C>(f: (A, B) -> C) -> A -> B -> C {

return { a in { b in f(a, b) } } }

Generics

func printEach<T: SequenceType>(items: T) { for item in items { print(item) } }

printEach(1...5) printEach(["one", "two", "three"])

Type Inference

let x = 42.0 x.dynamicType // Double x is Double // true

Type Inference

var xs = [1, 5, 2, 4, 3] xs.sort(<) print(xs) // [1, 2, 3, 4, 5]

Type Inference

var xs = [1, 5, 2, 4, 3] xs.sort(<) print(xs) // [1, 2, 3, 4, 5]

Type Inference

let xs = [1, 5, 2, 4, 3] let ys = xs.sorted(<) print(xs) // [1, 5, 2, 4, 3] print(ys) // [1, 2, 3, 4, 5]

Type Inference

let xs = [1, 5, 2, 4, 3] let ys = xs.sorted(<) print(xs) // [1, 5, 2, 4, 3] print(ys) // [1, 2, 3, 4, 5]

Enumerationsenum Fruit: String { case Apple = "apple" case Banana = "banana" case Cherry = "cherry" }

Fruit.Apple.rawValue // "apple"

Enumerations

enum ValidationResult { case Valid case NotValid(NSError) }

Enumerationsenum MyApi { case xAuth(String, String) case GetUser(Int) } extension MyApi: MoyaTarget { var baseURL: NSURL { return NSURL(string: "")! }

var path: String { switch self { case .xAuth: return "/authorise" case .GetUser(let id): return "/user/\(id)" } } }

https://github.com/Moya/Moya

Optionalsenum Optional<T> { case None case Some(T) }

var x = 5 x = nil // Error!

Optional Chainingstruct Dog { var name: String } struct Person { var dog: Dog? }

let dog = Dog(name: "Dodge") let person = Person(dog: dog) let dogName = person.dog?.name

Optional Chainingstruct Dog { var name: String } struct Person { var dog: Dog? }

let dog = Dog(name: "Dodge") let person = Person(dog: dog) let dogName = person.dog?.name

Optional Chaining

Functors, Applicatives,

Monads

Functors, Applicatives, Monads

let x = 2 x + 3 // == 5

Functors, Applicatives, Monads

let x = 2 x + 3 // == 5

let y = Optional(2)

Functors

let y = Optional(2) y + 3

// Error! // Value of optional type // Optional<Int> not unwrapped

Functors

let y = Optional(2) y.map { $0 + 3 }

// Optional(5)

Functorsfunc map<U>(f: T -> U) -> U? { switch self { case .Some(let x): return f(x) case .None: return .None } }

Functors

infix operator <^> { associativity left

}

func <^><T, U>(f: T -> U, a: T?) -> U? { return a.map(f) }

Functors

func <^><T, U>(f: T -> U, a: T?) -> U? { return a.map(f) }

let addOne = { $0 + 1 }

addOne <^> Optional(2) // Optional(3)

Applicativefunc apply<U>(f: (T -> U)?) -> U? { switch f { case .Some(let someF): return self.map(someF) case .None: return .None } }

Applicatives

infix operator <*> { associativity left }

func <*><T, U>(f: (T -> U)?, a: T?) -> U? { return a.apply(f) }

Applicatives

infix operator <*> { associativity left }

func <*><T, U>(f: (T -> U)?, a: T?) -> U? { return a.apply(f) }

func add(a: Int)(b: Int) -> Int { return a + b }

Applicatives

add <^> Optional(2) <*> Optional(3) // Optional(5)

Applicatives

add <^> Optional(2) <*> Optional(3) // Optional(5)

Applicatives

add <^> Optional(2) <*> Optional(3) // Optional(5)

let a = add <^> Optional(2)

Applicatives

add <^> Optional(2) <*> Optional(3) // Optional(5)

let a = add <^> Optional(2)

Applicatives

add <^> Optional(2) <*> Optional(3) // Optional(5)

let a = add <^> Optional(2)

let a: (b: Int) -> Int?

Monadstypealias T = Double let f: T -> T = { $0 * 2.0 } let g: (T, T) -> T = { $0 / $1 }

Monadstypealias T = Double let f: T -> T = { $0 * 2.0 } let g: (T, T) -> T = { $0 / $1 }

f(g(4, 2))

Monadstypealias T = Double let f: T -> T = { $0 * 2.0 } let g: (T, T) -> T = { $0 / $1 }

f(g(4, 2))

g: (T, T) -> T?

Monadstypealias T = Double let f: T -> T = { $0 * 2.0 } let g: (T, T) -> T = { $0 / $1 }

f(g(4, 2))

g: (T, T) -> T?

g(4, 2) >>- { f($0) }

Monads

>>-==

http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html

Monadsfunc flatten<U>(a: U??) -> U? { switch a { case .Some(let someA): return someA case .None: return .None } }

Monadsfunc flatMap<U>(f: T -> U?) -> U? { return flatten(map(f)) }

Monadsfunc flatMap<U>(f: T -> U?) -> U? { return flatten(map(f)) }

func map<U>(f: T -> U) -> U?

Monadsfunc flatMap<U>(f: T -> U?) -> U? { return flatten(map(f)) }

func map<U>(f: T -> U) -> U?

Monadsfunc flatMap<U>(f: T -> U?) -> U? { return flatten(map(f)) }

func map<U>(f: T -> U) -> U?

func map<U?>(f: T -> U?) -> U??

Monads

infix operator >>- { associativity left }

func >>-<T, U>(a: T?, f: T -> U?) -> U? { return a.flatMap(f) }

Monadsfunc half(a: Int) -> Int? { return a % 2 == 0 ? a / 2 : .None }

Monadsfunc half(a: Int) -> Int? { return a % 2 == 0 ? a / 2 : .None }

Optional(8) >>- half >>- half // Optional(2)

Monad Laws

• Left Identity

• Right Identity

• Associativity

Left Identity Lawlet f = { Optional($0 + 1) } let a = 1

let x = Optional(a) >>- f let y = f(a)

x == y

Right Identity Lawfunc create<T>(value: T) -> T? { return Optional(value) }

let x = Optional(1) >>- create let y = Optional(1)

x == y

Associativity Law

let double = { Optional(2 * $0) } let triple = { Optional(3 * $0) }

let x = Optional(1) >>- double >>- triple let y = Optional(1) >>- { double($0) >>- triple } let z = { Optional(1) >>- double }() >>- triple

x == y y == z

RecapFunctor map<U>(f: T -> U) -> M<U>

Applicative apply<U>(f: M<(T -> U)>) -> M<U>

Monad flatMap<U>(f: T -> M<U>) -> M<U>

Pipes & Railways

@ScottWlaschin

Pipesinfix operator |> { associativity left }

public func |> <T, U>(x: T, f: T -> U) -> U { return f(x) }

let addTwo = { $0 + 2 } let prodThree = { $0 * 3 }

5 |> addTwo |> prodThree |> print // 21

Pipeslet transformedX = x |> addTwo |> prodThree |> increment |> square |> pow

VS (pow(square(increment(prodThree(addTwo(x))))))

Railways

http://fsharpforfunandprofit.com/posts/recipe-part2/

Argo JSON Parser

+

Argo Runes

Argo Exampleextension Model: Decodable { static func decode(json: JSON) -> Decoded<Model> {

return Model.create <^> json <| "id" <*> json <| "room" <*> json <| "guest_name" <*> json <| "status" <*> json <| "label" <*> json <|? "user_comment" <*> json <| ["channel", "label"] <*> json <| "severity" <*> json <|| "epochs" <*> json <|| "body" } }

Argo Example

let entities: [Model]? entities = data?.json() >>- { $0["entities"] } >>- decode

Where Next?

Thanks!

Comments / Questions?

@aleks_voronova-voronov