Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Alexander Voronov

Alexander Voronov

Swift: Going Functional
https://youtu.be/Dc9aKhs37BE

Oleksandr Voronov

September 15, 2015
Tweet

More Decks by Oleksandr Voronov

Other Decks in Programming

Transcript

  1. First Class Functions func add(x: Int) -> Int -> Int

    { return { y in y + x } } let addOne = add(1) addOne(2) // 3
  2. First Class Functions func addTwo(x: Int) -> Int { return

    x + 2 } (1...5).map(addTwo) // [3, 4, 5, 6, 7]
  3. Currying func 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]
  4. Currying func curry<A, B, C>(f: (A, B) -> C) ->

    A -> B -> C { return { a in { b in f(a, b) } } }
  5. Generics func printEach<T: SequenceType>(items: T) { for item in items

    { print(item) } } printEach(1...5) printEach(["one", "two", "three"])
  6. Type Inference var xs = [1, 5, 2, 4, 3]

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

    xs.sort(<) print(xs) // [1, 2, 3, 4, 5]
  8. 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]
  9. 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]
  10. Enumerations enum Fruit: String { case Apple = "apple" case

    Banana = "banana" case Cherry = "cherry" } Fruit.Apple.rawValue // "apple"
  11. Enumerations enum 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
  12. Optional Chaining struct Dog { var name: String } struct

    Person { var dog: Dog? } let dog = Dog(name: "Dodge") let person = Person(dog: dog) let dogName = person.dog?.name
  13. Optional Chaining struct 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
  14. Functors let y = Optional(2) y + 3 // Error!

    // Value of optional type // Optional<Int> not unwrapped
  15. Functors func map<U>(f: T -> U) -> U? { switch

    self { case .Some(let x): return f(x) case .None: return .None } }
  16. Functors infix operator <^> { associativity left } func <^><T,

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

    U? { return a.map(f) } let addOne = { $0 + 1 } addOne <^> Optional(2) // Optional(3)
  18. Applicative func apply<U>(f: (T -> U)?) -> U? { switch

    f { case .Some(let someF): return self.map(someF) case .None: return .None } }
  19. Applicatives infix operator <*> { associativity left } func <*><T,

    U>(f: (T -> U)?, a: T?) -> U? { return a.apply(f) }
  20. 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 }
  21. Applicatives add <^> Optional(2) <*> Optional(3) // Optional(5) let a

    = add <^> Optional(2) let a: (b: Int) -> Int?
  22. Monads typealias T = Double let f: T -> T

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

    = { $0 * 2.0 } let g: (T, T) -> T = { $0 / $1 } f(g(4, 2))
  24. Monads typealias T = Double let f: T -> T

    = { $0 * 2.0 } let g: (T, T) -> T = { $0 / $1 } f(g(4, 2)) g: (T, T) -> T?
  25. Monads typealias 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) }
  26. Monads func flatten<U>(a: U??) -> U? { switch a {

    case .Some(let someA): return someA case .None: return .None } }
  27. Monads func flatMap<U>(f: T -> U?) -> U? { return

    flatten(map(f)) } func map<U>(f: T -> U) -> U?
  28. Monads func flatMap<U>(f: T -> U?) -> U? { return

    flatten(map(f)) } func map<U>(f: T -> U) -> U?
  29. Monads func flatMap<U>(f: T -> U?) -> U? { return

    flatten(map(f)) } func map<U>(f: T -> U) -> U? func map<U?>(f: T -> U?) -> U??
  30. Monads infix operator >>- { associativity left } func >>-<T,

    U>(a: T?, f: T -> U?) -> U? { return a.flatMap(f) }
  31. Monads func half(a: Int) -> Int? { return a %

    2 == 0 ? a / 2 : .None } Optional(8) >>- half >>- half // Optional(2)
  32. Left Identity Law let f = { Optional($0 + 1)

    } let a = 1 let x = Optional(a) >>- f let y = f(a) x == y
  33. Right Identity Law func create<T>(value: T) -> T? { return

    Optional(value) } let x = Optional(1) >>- create let y = Optional(1) x == y
  34. 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
  35. Recap Functor 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>
  36. Pipes infix 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
  37. Pipes let transformedX = x |> addTwo |> prodThree |>

    increment |> square |> pow VS (pow(square(increment(prodThree(addTwo(x))))))
  38. Argo Example extension 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" } }
  39. Where Next • Functors, Applicatives and Monads in Pictures •

    Railway Oriented Programming • Functional Programming in Swift (Objc.io) • Argo • Swiftz • RxSwift • ReactiveCocoa-3.0 • Haskell, F#, Erlang, Elm