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

Finding Happiness in Functional Programming

Finding Happiness in Functional Programming

Brandon Williams

October 01, 2016
Tweet

More Decks by Brandon Williams

Other Decks in Programming

Transcript

  1. Isolation of side-effects An expression is said to have a

    side-effect if its execution makes an observable change to the outside world.
  2. Isolation of side-effects func update(text: String, forLabel: UILabel) { label.text

    = text } update(text: user.name, forLabel: self.titleLabel)
  3. Isolation of side-effects func updateLoginButtonEnabled() { self.loginButton.enabled = !self.userTextField.text.isEmpty &&

    !self.passwordTextField.text.isEmpty } func emailChanged() { self.updateLoginButtonEnabled() } func passwordChanged() { self.updateLoginButtonEnabled() }
  4. Isolation of side-effects // Pure, functional world let emailChanged: Signal<String,

    NoError> let passwordChanged: Signal<String, NoError> let loginButtonEnabled = combineLatest(emailChanged, passwordChanged) .map { !$0.isEmpty && !$1.isEmpty } // Side-effect world loginButtonEnabled.observeNext { [weak self] in self?.loginButtonEnabled.enabled = $0 }
  5. Isolation of side-effects // Pure, functional world let emailChanged: Signal<String,

    NoError> let passwordChanged: Signal<String, NoError> let loginButtonEnabled = combineLatest(emailChanged, passwordChanged) .map { !$0.isEmpty && !$1.isEmpty } // Side-effect world self.loginButton.rac.enabled = loginButtonEnabled
  6. Surfacing of co-effects If an effect is a change to

    the outside world after executing an expression...
  7. Surfacing of co-effects If an effect is a change to

    the outside world after executing an expression... ...then...
  8. Surfacing of co-effects If an effect is a change to

    the outside world after executing an expression... ...then... ...a co-effect is the state of the world that the expression needs in order to execute.
  9. Surfacing of co-effects Dependency Injection func currentUserIsCreator(ofProject project: Project) ->

    Bool { return User.currentUser.id == project.creator.id } currentUserIsCreator(ofProject: project) // => true or false
  10. Surfacing of co-effects Dependency Injection func user(_ user: User, isCreatorOfProject:

    Project) -> Bool { return user.id == project.creator.id } user(User.currentUser, isCreatorOfProject: project) // => true or false
  11. Surfacing of co-effects References — Colin Barrett — Functional Swift

    Conference 2015 — Structure and Interpretation of Swift Programs — The work of Tomas Petricek — Coeffects: A calculus of context-dependent computation — Coeffects: The next big programming challenge
  12. Code to the interface you wish you had, not the

    interface you were given. - Stephen Celis
  13. An interface we were given Storyboards — Very thick abstraction

    layer — Separates code from data — Constantly catching up to what UIKit can do
  14. An interface we wish we had Lenses struct Project {

    let creator: User let id: Int let name: String }
  15. An interface we wish we had Lenses Project.lens.name // =>

    Lens<Project, String> Project.lens.name .~ "Advanced Swift" // => Project -> Project
  16. An interface we wish we had Lenses Project.lens.name // =>

    Lens<Project, String> Project.lens.name .~ "Advanced Swift" // => Project -> Project project |> Project.lens.name .~ "Advanced Swift"
  17. An interface we wish we had Lenses project |> Project.lens.name

    .~ "Advanced Swift" |> Project.lens.creator.name .~ "Chris Eidhof"
  18. An interface we wish we had UIKit Lenses UIView.lens.backgroundColor //

    => Lens<UIView, UIColor> UIView.lens.backgroundColor .~ .redColor() // => UIView -> UIView
  19. An interface we wish we had UIKit Lenses UIView.lens.backgroundColor //

    => Lens<UIView, UIColor> UIView.lens.backgroundColor .~ .redColor() // => UIView -> UIView view |> UIView.lens.backgroundColor .~ .redColor() |> UIView.lens.layer.cornerRadius .~ 4 |> UIView.lens.layer.masksToBounds .~ true
  20. An interface we wish we had UIKit Lenses func roundedStyle(cornerRadius:

    CGFloat) -> (UIView) -> UIView { return UIView.lens.layer.cornerRadius .~ 4 <> UIView.lens.layer.masksToBounds .~ true } view |> roundedStyle(cornerRadius: 4) |> UIView.lens.backgroundColor .~ .redColor()
  21. An interface we wish we had UIKit Lenses let baseButtonStyle

    = roundedStyle(cornerRadius: 4) <> UIButton.lens.titleLabel.font .~ UIFont(size: 16) <> UIButton.lens.contentEdgeInsets .~ .init(topBottom: 6, leftRight: 12) let greenButtonStyle = baseButtonStyle <> UIButton.lens.backgroundColor(forState: .Normal) .~ .greenColor()
  22. An interface we wish we had UIKit Lenses let bigButtonStyle

    = baseButtonStyle <> UIButton.lens.contentEdgeInsets %~ { .init(top: $0.top * 2, left: $0.left * 2, bottom: $0.bottom * 2, right: $0.right * 2) }
  23. An interface we wish we had UIKit Lenses let baseButtonStyle

    = roundedStyle(cornerRadius: 4) <> UIButton.lens.titleLabel.font %~~ { _, button in button.traitCollection.verticalSizeClass == .Compact ? UIFont(size: 12) : UIFont(size: 14) } <> UIButton.lens.contentEdgeInsets .~ .init(topBottom: 6, leftRight: 12)
  24. Principles that we did not benefit so much from: —

    D.R.Y. — S.R.P. — S.O.L.I.D. — Objects