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

Demystifying Functional Programming

Demystifying Functional Programming

Tomás Ruiz-López

December 17, 2020
Tweet

More Decks by Tomás Ruiz-López

Other Decks in Programming

Transcript

  1. Total func divide(_ x: Double, _ y: Double) -> Double

    { guard y != 0 else { fatalError("Denominator cannot be zero") } return x / y }
  2. Total func divide(_ x: Double, _ y: Double) throws ->

    Double { guard y != 0 else { throw DivideError.divisionByZero } return x / y }
  3. Total func divide(_ x: Double, _ y: Double) -> Result<Double,

    DivideError> { guard y != 0 else { return .failure(.divisionByZero) } return .success(x / y) }
  4. Pure func greet(name: String) -> Void { print("Hello \(name)!") }

    greet(name: “Swifters") > Hello Swifters!
  5. Pure func greet(name: String) -> AnyPublisher<Void, Never> { Future {

    promise in print("Hello \(name)!") promise(.success(())) }.eraseToAnyPublisher() }
  6. Pure func greet(name: String) -> AnyPublisher<Void, Never> { Future {

    promise in print("Hello \(name)!") promise(.success(())) }.eraseToAnyPublisher() } let publisher = greet(name: “Swifters") > Hello Swifters!
  7. Pure func greet(name: String) -> AnyPublisher<Void, Never> { Deferred {

    Future { promise in print("Hello \(name)!") promise(.success(())) } }.eraseToAnyPublisher() }
  8. Pure func greet(name: String) -> AnyPublisher<Void, Never> { Deferred {

    Future { promise in print("Hello \(name)!") promise(.success(())) } }.eraseToAnyPublisher() } let publisher = greet(name: “Swifters") >
  9. Pure func greet(name: String) -> AnyPublisher<Void, Never> { Deferred {

    Future { promise in print("Hello \(name)!") promise(.success(())) } }.eraseToAnyPublisher() } let cancellable = greet(name: “Swifters").sink { _ in } > Hello Swifters!
  10. Quiz How many times does it print “Hello Swifters!”? func

    greet(name: String) -> AnyPublisher<Void, Never> { Future { promise in print("Hello \(name)!") promise(.success(())) }.eraseToAnyPublisher() }
  11. Quiz How many times does it print “Hello Swifters!”? func

    greet(name: String) -> AnyPublisher<Void, Never> { Future { promise in print("Hello \(name)!") promise(.success(())) }.eraseToAnyPublisher() } let cancellable = greet(name: "Swifters").flatMap { _ in greet(name: “Swifters") }.sink { _ in }
  12. Quiz How many times does it print “Hello Swifters!”? func

    greet(name: String) -> AnyPublisher<Void, Never> { Future { promise in print("Hello \(name)!") promise(.success(())) }.eraseToAnyPublisher() } let cancellable = greet(name: "Swifters").flatMap { _ in greet(name: “Swifters") }.sink { _ in } Solution: 2
  13. Quiz How many times does it print “Hello Swifters!”? func

    greet(name: String) -> AnyPublisher<Void, Never> { Future { promise in print("Hello \(name)!") promise(.success(())) }.eraseToAnyPublisher() } let publisher = greet(name: “Swifters") let cancellable = publisher.flatMap { _ in publisher }.sink { _ in }
  14. Quiz How many times does it print “Hello Swifters!”? func

    greet(name: String) -> AnyPublisher<Void, Never> { Future { promise in print("Hello \(name)!") promise(.success(())) }.eraseToAnyPublisher() } let publisher = greet(name: “Swifters") let cancellable = publisher.flatMap { _ in publisher }.sink { _ in } Solution: 1
  15. Quiz How many times does it print “Hello Swifters!”? func

    greet(name: String) -> AnyPublisher<Void, Never> { Deferred { Future { promise in print("Hello \(name)!") promise(.success(())) } }.eraseToAnyPublisher() }
  16. Quiz How many times does it print “Hello Swifters!”? let

    cancellable = greet(name: "Swifters").flatMap { _ in greet(name: “Swifters") }.sink { _ in } func greet(name: String) -> AnyPublisher<Void, Never> { Deferred { Future { promise in print("Hello \(name)!") promise(.success(())) } }.eraseToAnyPublisher() }
  17. Quiz How many times does it print “Hello Swifters!”? let

    cancellable = greet(name: "Swifters").flatMap { _ in greet(name: “Swifters") }.sink { _ in } Solution: 2 func greet(name: String) -> AnyPublisher<Void, Never> { Deferred { Future { promise in print("Hello \(name)!") promise(.success(())) } }.eraseToAnyPublisher() }
  18. Quiz How many times does it print “Hello Swifters!”? func

    greet(name: String) -> AnyPublisher<Void, Never> { Deferred { Future { promise in print("Hello \(name)!") promise(.success(())) } }.eraseToAnyPublisher() } let publisher = greet(name: “Swifters") let cancellable = publisher.flatMap { _ in publisher }.sink { _ in }
  19. Quiz How many times does it print “Hello Swifters!”? Solution:

    2 func greet(name: String) -> AnyPublisher<Void, Never> { Deferred { Future { promise in print("Hello \(name)!") promise(.success(())) } }.eraseToAnyPublisher() } let publisher = greet(name: “Swifters") let cancellable = publisher.flatMap { _ in publisher }.sink { _ in }
  20. Pure func greet(name: String) -> IO<Never, Void> { IO.invoke {

    print("Hello \(name)!") } } greet(name: “Swifters").unsafeRunSync() > Hello Swifters! bow-swift.io
  21. Composition func compose<A, B, C>( _ g: @escaping (B) ->

    C, _ f: @escaping (A) -> B ) -> (A) -> C { { a in g(f(a)) } }
  22. Composition func compose<A, B, C>( _ g: @escaping (B) ->

    C, _ f: @escaping (A) -> B ) -> (A) -> C { { a in g(f(a)) } } B C A
  23. Composition func compose<A, B, C>( _ g: @escaping (B) ->

    C, _ f: @escaping (A) -> B ) -> (A) -> C { { a in g(f(a)) } } B C A g
  24. Composition func compose<A, B, C>( _ g: @escaping (B) ->

    C, _ f: @escaping (A) -> B ) -> (A) -> C { { a in g(f(a)) } } B C A f g
  25. Composition func compose<A, B, C>( _ g: @escaping (B) ->

    C, _ f: @escaping (A) -> B ) -> (A) -> C { { a in g(f(a)) } } B C A f g g · f
  26. Composition func andThen<A, B, C>( _ f: @escaping (A) ->

    B, _ g: @escaping (B) -> C ) -> (A) -> C { { a in g(f(a)) } } B C A f g g · f
  27. Composition func compose<A, B, C>( _ f: @escaping (A) ->

    B?, _ g: @escaping (B) -> C ) -> (A) -> ??? { // What goes here? }
  28. Composition B? A f func compose<A, B, C>( _ f:

    @escaping (A) -> B?, _ g: @escaping (B) -> C ) -> (A) -> ??? { // What goes here? }
  29. Composition B? A f C g B func compose<A, B,

    C>( _ f: @escaping (A) -> B?, _ g: @escaping (B) -> C ) -> (A) -> ??? { // What goes here? }
  30. Composition B? A f C g B func compose<A, B,

    C>( _ f: @escaping (A) -> B?, _ g: @escaping (B) -> C ) -> (A) -> ??? { // What goes here? }
  31. Composition B? A f C g B C? map func

    compose<A, B, C>( _ f: @escaping (A) -> B?, _ g: @escaping (B) -> C ) -> (A) -> ??? { // What goes here? }
  32. Composition func compose<A, B, C>( _ f: @escaping (A) ->

    B?, _ g: @escaping (B) -> C ) -> (A) -> C? { { a in f(a).map(g) } } B? A f C g B C? map
  33. Composition func compose<A, B, C>( _ f: @escaping (A) ->

    [B], _ g: @escaping (B) -> C ) -> (A) -> [C] { { a in f(a).map(g) } } func compose<A, B, C>( _ f: @escaping (A) -> Result<B, Error>, _ g: @escaping (B) -> C ) -> (A) -> Result<C, Error> { { a in f(a).map(g) } }
  34. Functor Compose functions using map func compose<F: Functor, A, B,

    C>( _ f: @escaping (A) -> F<B>, _ g: @escaping (B) -> C ) -> (A) -> F<C> { { a in f(a).map(g) } }
  35. Functor Compose functions using map func compose<F: Functor, A, B,

    C>( _ f: @escaping (A) -> Kind<F, B>, _ g: @escaping (B) -> C ) -> (A) -> Kind<F, C> { { a in f(a).map(g) } } bow-swift.io
  36. Composition func compose<A, B, C>( _ f: @escaping (A) ->

    B?, _ g: @escaping (B) -> C? ) -> ??? { // What goes here? }
  37. Composition B? A f func compose<A, B, C>( _ f:

    @escaping (A) -> B?, _ g: @escaping (B) -> C? ) -> ??? { // What goes here? }
  38. Composition B? A f C? g B func compose<A, B,

    C>( _ f: @escaping (A) -> B?, _ g: @escaping (B) -> C? ) -> ??? { // What goes here? }
  39. Composition B? A f C? g B func compose<A, B,

    C>( _ f: @escaping (A) -> B?, _ g: @escaping (B) -> C? ) -> ??? { // What goes here? }
  40. Composition B? A f C? g B C? f latMap

    func compose<A, B, C>( _ f: @escaping (A) -> B?, _ g: @escaping (B) -> C? ) -> ??? { // What goes here? }
  41. Composition B? A f C? g B C? f latMap

    func compose<A, B, C>( _ f: @escaping (A) -> B?, _ g: @escaping (B) -> C? ) -> (A) -> C? { { a in f(a).flatMap(g) } }
  42. Composition func compose<A, B, C>( _ f: @escaping (A) ->

    [B], _ g: @escaping (B) -> [C] ) -> (A) -> [C] { { a in f(a).flatMap(g) } } func compose<A, B, C>( _ f: @escaping (A) -> Result<B, Error>, _ g: @escaping (B) -> Result<C, Error> ) -> (A) -> Result<C, Error> { { a in f(a).flatMap(g) } }
  43. Monad Compose functions using f latMap func compose<F: Monad, A,

    B, C>( _ f: @escaping (A) -> F<B>, _ g: @escaping (B) -> F<C> ) -> (A) -> F<C> { { a in f(a).flatMap(g) } }
  44. Monad Compose functions using f latMap func compose<F: Monad, A,

    B, C>( _ f: @escaping (A) -> Kind<F, B>, _ g: @escaping (B) -> Kind<F, C> ) -> (A) -> Kind<F, C> { { a in f(a).flatMap(g) } } bow-swift.io
  45. Composition func zip<A, B, C>( _ a: A?, _ b:

    B?, with f: @escaping (A, B) -> C ) -> ??? { // What goes here? }
  46. Composition func zip<A, B, C>( _ a: A?, _ b:

    B?, with f: @escaping (A, B) -> C ) -> ??? { // What goes here? } A? B?
  47. Composition func zip<A, B, C>( _ a: A?, _ b:

    B?, with f: @escaping (A, B) -> C ) -> ??? { // What goes here? } A? B? A B C f
  48. Composition func zip<A, B, C>( _ a: A?, _ b:

    B?, with f: @escaping (A, B) -> C ) -> ??? { // What goes here? } A? B? A B C f
  49. Composition func zip<A, B, C>( _ a: A?, _ b:

    B?, with f: @escaping (A, B) -> C ) -> ??? { // What goes here? } A? B? A B C f C? zip
  50. Composition func zip<A, B, C>( _ a: A?, _ b:

    B?, with f: @escaping (A, B) -> C ) -> C? { a.flatMap { x in b.map { y in f(x, y) } } } A? B? A B C f C? zip
  51. Composition func zip<A, B, C>( _ a: [A], _ b:

    [B], with f: @escaping (A, B) -> C ) -> [C] { a.flatMap { x in b.map { y in f(x, y) } } } func zip<A, B, C>( _ a: Result<A, Error>, _ b: Result<B, Error>, with f: @escaping (A, B) -> C ) -> Result<C, Error> { a.flatMap { x in b.map { y in f(x, y) } } }
  52. Composition func loadWebResource(_ path: String) -> Resource? func decodeImage(_ r1:

    Resource, _ r2: Resource) -> Image? func dewarpAndCleanup(_ image: Image) -> Image? func processImageData() -> Image? { loadWebResource("dataprofile.txt").flatMap { dataRes in loadWebResource("imagedata.dat").flatMap { imageRes in decodeImage(dataRes, imageRes).flatMap { imageTmp in dewarpAndCleanup(imageTmp) } } } }
  53. Composition func loadWebResource(_ path: String) -> Resource? func decodeImage(_ r1:

    Resource, _ r2: Resource) -> Image? func dewarpAndCleanup(_ image: Image) -> Image? func processImageData() -> Image? { loadWebResource("dataprofile.txt").flatMap { dataRes in loadWebResource("imagedata.dat").flatMap { imageRes in decodeImage(dataRes, imageRes).flatMap { imageTmp in dewarpAndCleanup(imageTmp) } } } }
  54. Composition func loadWebResource(_ path: String) -> Resource? func decodeImage(_ r1:

    Resource, _ r2: Resource) -> Image? func dewarpAndCleanup(_ image: Image) -> Image? func processImageData() -> Image? { if let dataRes = loadWebResource("dataprofile.txt"), let imageRes = loadWebResource("imagedata.dat"), let imageTmp = decodeImage(dataRes, imageRes) { return dewarpAndCleanup(imageTmp) } else { return nil } }
  55. Composition func loadWebResource(_ path: String) -> Result<Resource, Error> func decodeImage(_

    r1: Resource, _ r2: Resource) -> Result<Image, Error> func dewarpAndCleanup(_ image: Image) -> Result<Image, Error> func processImageData() -> Result<Image, Error> { loadWebResource("dataprofile.txt").flatMap { dataRes in loadWebResource("imagedata.dat").flatMap { imageRes in decodeImage(dataRes, imageRes).flatMap { imageTmp in dewarpAndCleanup(imageTmp) } } } }
  56. Composition func loadWebResource(_ path: String) -> AnyPublisher<Resource, Error> func decodeImage(_

    r1: Resource, _ r2: Resource) -> AnyPublisher<Image, Error> func dewarpAndCleanup(_ image: Image) -> AnyPublisher<Image, Error> func processImageData() -> AnyPublisher<Image, Error> { loadWebResource("dataprofile.txt").flatMap { dataRes in loadWebResource("imagedata.dat").flatMap { imageRes in decodeImage(dataRes, imageRes).flatMap { imageTmp in dewarpAndCleanup(imageTmp) } } } }
  57. Composition func loadWebResource(_ path: String) async throws -> Resource func

    decodeImage(_ r1: Resource, _ r2: Resource) async throws -> Image func dewarpAndCleanup(_ image: Image) async throws -> Image func processImageData() async throws -> Image { let dataRes = await try loadWebResource("dataprofile.txt") let imageRes = await try loadWebResource("imagedata.dat") let imageTmp = await try decodeImage(dataRes, imageRes) return await try dewarpAndCleanup(imageTmp) }
  58. Composition func processImageData() -> IO<Error, Image> { let dataRes =

    IO<Error, Resource>.var() let imageRes = IO<Error, Resource>.var() let imageTmp = IO<Error, Image>.var() let image = IO<Error, Image>.var() return binding { dataRes <- loadWebResource("dataProfile.txt") imageRes <- loadWebResource("imagedata.dat") imageTmp <- decode(dataRes.get, imageRes.get) image <- dewarpAndCleanup(imageTmp.get) } yield: { image.get }^ } bow-swift.io