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

Finding Happiness in Functional Programming

Finding Happiness in Functional Programming

Avatar for Brandon Williams

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