$30 off During Our Annual Pro Sale. View Details »

Functional programming for UI

Teddy Ku
November 14, 2018

Functional programming for UI

Turn the pyramid of doom into a line of happiness

Teddy Ku

November 14, 2018
Tweet

More Decks by Teddy Ku

Other Decks in Programming

Transcript

  1. Teddy Ku
    'VODUJPOBMQSPHSBNNJOHGPS6*

    View Slide

  2. 2
    Copyright © Merpay, Inc. All Rights Reserved.
    5FEEZ,V
    !ULVJDIPPTFZPV
    !ULVJDIPPTFZPV
    4UBUVT

    View Slide

  3. 3
    Copyright © Merpay, Inc. All Rights Reserved.
    'FBUVSF
    0OCPBSEJOHUVUPSJBMT

    View Slide

  4. 4
    Copyright © Merpay, Inc. All Rights Reserved.
    'FBUVSF
    0OCPBSEJOHUVUPSJBMT

    View Slide

  5. 5
    0OCPBSEJOHUVUPSJBMT
    Copyright © Merpay, Inc. All Rights Reserved.

    View Slide

  6. 6
    Copyright © Merpay, Inc. All Rights Reserved.
    class BalloonView: UIView {
    var onTapped: (() -> Void)?
    var contentView: UIView
    func show() { /* ... */ }
    func dismiss() { /* ... */ }
    /* ... */
    }

    View Slide

  7. 7
    Copyright © Merpay, Inc. All Rights Reserved.
    class ViewController: UIViewController {
    func showTutorialFlow() {
    let tutorialOne = tutorialOneBalloonView()
    let tutorialTwo = tutorialTwoBalloonView()
    let tutorialThree = tutorialThreeBalloonView()
    tutorialOne.onTapped = { [weak tutorialOne] in
    tutorialOne?.dismiss()
    tutorialTwo.show()
    }
    tutorialTwo.onTapped = { [weak tutorialTwo] in
    tutorialTwo?.dismiss()
    tutorialThree.show()
    }
    tutorialThree.onTapped = { [weak self, weak tutorialThree] in
    tutorialThree?.dismiss()
    self?.hideGrayOverlay { }
    }
    showGrayOverlay {
    tutorialOne.show()
    }
    }

    View Slide

  8. 8
    Copyright © Merpay, Inc. All Rights Reserved.
    class ViewController: UIViewController {
    func showTutorialFlow() {
    let tutorialOne = tutorialOneBalloonView()
    let tutorialTwo = tutorialTwoBalloonView()
    let tutorialThree = tutorialThreeBalloonView()
    %PO`UXBOUUPJOTUBOUJBUFFWFSZUIJOHVQGSPOU
    0OMZOFFEPOFWJFXBUBUJNF

    View Slide

  9. 9
    Copyright © Merpay, Inc. All Rights Reserved.
    3FXSJUFPOFWJFXBUBUJNF

    View Slide

  10. class ViewController: UIViewController {
    func showTutorialFlow() {
    let tutorialOne = tutorialOneBalloonView()
    tutorialOne.onTapped = { [weak tutorialOne] in
    tutorialOne?.dismiss()
    let tutorialTwo = tutorialTwoBalloonView()
    tutorialTwo.onTapped = { [weak tutorialTwo] in
    tutorialTwo?.dismiss()
    let tutorialThree = tutorialThreeBalloonView()
    tutorialThree.onTapped = { [weak self, weak tutorialThree] in
    tutorialThree?.dismiss()
    self?.hideGrayOverlay { }
    }
    tutorialThree.show()
    }
    tutorialTwo.show()
    }
    showGrayOverlay {
    tutorialOne.show()
    }
    }
    10
    Copyright © Merpay, Inc. All Rights Reserved.
    Pyramid of doom

    View Slide

  11. 11
    Copyright © Merpay, Inc. All Rights Reserved.
    /FTUFEDMPTVSFT
    )PXUPEFBMXJUIUIFN

    View Slide

  12. 12
    Copyright © Merpay, Inc. All Rights Reserved.
    'VODUJPOTJOGVODUJPOT
    -FU`TVTFGVODUJPOT
    'VODUJPOBM1SPHSBNNJOH

    View Slide

  13. 13
    Copyright © Merpay, Inc. All Rights Reserved.
    5IJOLUPQEPXO
    8IBUXPVMEUIFJEFBMTPMVUJPOMPPLMJLF

    View Slide

  14. 14
    Copyright © Merpay, Inc. All Rights Reserved.
    func showTutorialFlow() {
    let tutorialBalloon = tutorialOneBalloonView()
    let transitions = tutorialBalloon.onTapped({ inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialTwoBalloonView()
    }) >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialThreeBalloonView()
    } >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialFourBalloonView()
    } >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialFiveBalloonView()
    } >>> { [weak self] inputBalloonView in
    inputBalloonView?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    tutorialBalloon.show(onTapped: transitions)
    }
    $PNQPTBCMFUSBOTJUJPOGVODUJPOT

    View Slide

  15. 15
    Copyright © Merpay, Inc. All Rights Reserved.
    )PXXPVMEXFJNQMFNFOUUIJT

    View Slide

  16. 16
    Copyright © Merpay, Inc. All Rights Reserved.
    typealias BalloonTransition = (BalloonView?) -> BalloonView?
    // associativity: right
    infix operator >>>: FunctionArrowPrecedence
    func >>> (

    transitionOne: @escaping BalloonTransition, 

    transitionTwo: @escaping BalloonTransition) -> BalloonTransition {
    return { balloonView in
    balloonView?._nextTransition = transitionTwo
    return transitionOne(balloonView)
    }
    }
    1 >>> (2 >>> (3 >>> (4 >>> 5)))

    View Slide

  17. 17
    Copyright © Merpay, Inc. All Rights Reserved.
    func >>> (

    transitionOne: @escaping BalloonTransition, 

    transitionTwo: @escaping BalloonTransition) -> BalloonTransition {
    return { balloonView in
    balloonView?._nextTransition = transitionTwo
    return transitionOne(balloonView)
    }
    }
    1 >>> (2 >>> (3 >>> (4 >>> 5)))
    func showTutorialFlow() {
    let tutorialBalloon = tutorialOneBalloonView()
    let transitions = tutorialBalloon.onTapped({ inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialTwoBalloonView()
    }) >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialThreeBalloonView()
    } >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialFourBalloonView()
    } >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialFiveBalloonView()
    } >>> { [weak self] inputBalloonView in
    inputBalloonView?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    tutorialBalloon.show(onTapped: transitions)
    }

    View Slide

  18. 18
    Copyright © Merpay, Inc. All Rights Reserved.
    func showTutorialFlow() {
    let tutorialBalloon = tutorialOneBalloonView()
    let transitions = tutorialBalloon.onTapped({ inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialTwoBalloonView()
    }) >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialThreeBalloonView()
    } >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialFourBalloonView()
    } >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialFiveBalloonView()
    } >>> { [weak self] inputBalloonView in
    inputBalloonView?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    tutorialBalloon.show(onTapped: transitions)
    }
    func >>> (

    transitionOne: @escaping BalloonTransition, 

    transitionTwo: @escaping BalloonTransition) -> BalloonTransition {
    return { balloonView in
    balloonView?._nextTransition = transitionTwo
    return transitionOne(balloonView)
    }
    }
    } >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialFiveBalloonView()
    } >>> { [weak self] inputBalloonView in
    inputBalloonView?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    -BTUUXPDMPTVSFT

    View Slide

  19. Copyright © Merpay, Inc. All Rights Reserved.
    { balloon4 in
    balloon4.nextTransition = { [weak self] balloon5 in
    balloon5?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    balloon4?.dismiss()
    return tutorialFiveBalloonView()
    }
    } >>> { inputBalloonView in
    inputBalloonView?.dismiss()
    return tutorialFiveBalloonView()
    } >>> { [weak self] inputBalloonView in
    inputBalloonView?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    FYFDVUFXIFOCBMMPPOJTUBQQFE
    FYFDVUFXIFO
    CBMMPPOJTUBQQFE
    8IBUEPFTSFUVSOTBDMPTVSF OPUBDUVBMDPEF

    View Slide

  20. Copyright © Merpay, Inc. All Rights Reserved.
    balloon3.nextTransition = { balloon4 in
    balloon4.nextTransition = { [weak self] balloon5 in
    balloon5?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    balloon4?.dismiss()
    return tutorialFiveBalloonView()
    }
    balloon3?.dismiss()
    return tutorialFourBalloonView()
    GVODUJPOXJMMTFUUIFDMPTVSFUP
    UIFQSFWJPVT#BMMPPO7JFX
    8IBUEPFT OPUBDUVBMDPEF

    View Slide

  21. Copyright © Merpay, Inc. All Rights Reserved.
    balloon2.nextTransition = { balloon3 in
    balloon3.nextTransition = { balloon4 in
    balloon4.nextTransition = { [weak self] balloon5 in
    balloon5?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    balloon4?.dismiss()
    return tutorialFiveBalloonView()
    }
    balloon3?.dismiss()
    return tutorialFourBalloonView()
    }
    balloon2?.dismiss()
    return tutorialThreeBalloonView()
    8IBUEPFT OPUBDUVBMDPEF

    View Slide

  22. Copyright © Merpay, Inc. All Rights Reserved.
    tutorialBalloon.show(onTapped: { balloon1 in
    balloon1.nextTransition = { balloon2 in
    balloon2.nextTransition = { balloon3 in
    balloon3.nextTransition = { balloon4 in
    balloon4.nextTransition = { [weak self] balloon5 in
    balloon5?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    balloon4?.dismiss()
    return tutorialFiveBalloonView()
    }
    balloon3?.dismiss()
    return tutorialFourBalloonView()
    }
    balloon2?.dismiss()
    return tutorialThreeBalloonView()
    }
    balloon1?.dismiss()
    return tutorialTwoBalloonView()
    })
    8IBUEPFT OPUBDUVBMDPEF

    View Slide

  23. Copyright © Merpay, Inc. All Rights Reserved.
    tutorialBalloon.show(onTapped: { balloon1 in
    balloon1.nextTransition = { balloon2 in
    balloon2.nextTransition = { balloon3 in
    balloon3.nextTransition = { balloon4 in
    balloon4.nextTransition = { [weak self] balloon5 in
    balloon5?.dismiss()
    self?.hideGrayOverlay { }
    return nil
    }
    balloon4?.dismiss()
    return tutorialFiveBalloonView()
    }
    balloon3?.dismiss()
    return tutorialFourBalloonView()
    }
    balloon2?.dismiss()
    return tutorialThreeBalloonView()
    }
    balloon1?.dismiss()
    return tutorialTwoBalloonView()
    })

    View Slide

  24. 24
    Copyright © Merpay, Inc. All Rights Reserved.
    .JTTJPOBDDPNQMJTIFE
    3FBEBCMFDPEF
    0OMZPOF#BMMPPO7JFXJONFNPSZ

    View Slide

  25. 25
    Copyright © Merpay, Inc. All Rights Reserved.
    $VSSZJOH
    func add(x: Int) -> ((Int) -> Int) {
    return { y in return x + y }
    }
    // Removed in Swift 3
    // https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md
    func foo(x: Int)(y: Int)

    View Slide

  26. 26
    Copyright © Merpay, Inc. All Rights Reserved.
    typealias Filter = (CIImage) -> CIImage
    let myFilter = blur(blurRadius) >>> colorOverlay(overlayColor)
    let result = myFilter(image)
    *OTQJSBUJPO'VODUJPOBM4XJGU PCKDJP

    View Slide

  27. 27
    Copyright © Merpay, Inc. All Rights Reserved.
    4XJGU0CKFDUJWF$

    View Slide

  28. 28
    Copyright © Merpay, Inc. All Rights Reserved.
    5IBOLZPV
    HJUIVCDPNNFSDBSJ#BMMPPO7JFX

    View Slide