Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Introduction To Functional Reactive Programming Poznan

265 views

Published on

Slides from "Introduction To Functional Reactive Programming" presentation in Poznan 19.11.2016

Published in: Software
  • Be the first to comment

  • Be the first to like this

Introduction To Functional Reactive Programming Poznan

  1. 1. Introduction to Functional Reactive Programming @EliSawic
  2. 2. About me Eliasz Sawicki Blog: www.eliaszsawicki.com Twitter: @EliSawic @EliSawic
  3. 3. Agenda • What is functional reactive programming? • Working with streams • ReactiveCocoa - Thinking in signals • Example @EliSawic
  4. 4. Functional Reactive Programming @EliSawic
  5. 5. Wikipedia Functional reactive programming (FRP) is a programming paradigm for reactive programming (asynchronous dataflow programming) using the building blocks of functional programming (e.g. map, reduce, filter). @EliSawic
  6. 6. Reactive Programming @EliSawic
  7. 7. Asynchronous Dataflow @EliSawic
  8. 8. Reacting to state changes @EliSawic
  9. 9. Functional Programming @EliSawic
  10. 10. Immutable @EliSawic
  11. 11. assert(f(x) == f(x)) @EliSawic
  12. 12. A person class Person { let name: String let phoneNumber: String init(name: String, phoneNumber: String) { self.name = name self.phoneNumber = phoneNumber } } class MobilePhone { func call(person: Person) -> Bool { // implementation } } @EliSawic
  13. 13. Mutable let mobilePhone = MobilePhone() let john = Person(name: "John", phoneNumber: "123456789") func makeAPhoneCall(device: Phone, person: Person, countryCode: String) -> Bool { person.phoneNumber = countryCode + person.phoneNumber let success = device.call(person) return success } makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // false makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // false @EliSawic
  14. 14. Immutable let mobilePhone = MobilePhone() let john = Person(name: "John", phoneNumber: "123456789") func makeAPhoneCall(device: Phone, person: Person, countryCode: String) -> Bool { let prefixedPhoneNumber = countryCode + person.phoneNumber let newPerson = Person(name: person.name, phoneNumber: prefixedPhoneNumber) let success = device.call(newPerson) return success } makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true makeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true @EliSawic
  15. 15. Stateless @EliSawic
  16. 16. Stateful var value = 0 func increment() -> Int { value += 1 return value } @EliSawic
  17. 17. Stateless func increment(value: Int) -> Int { return value + 1 } @EliSawic
  18. 18. Imperative vs Declarative @EliSawic
  19. 19. Imperative @EliSawic
  20. 20. Imperative let array = [0, 1, 2, 3, 4, 5] var evenNumbers = [Int]() for element in array { if element % 2 == 0 { evenNumbers.append(element) } } @EliSawic
  21. 21. Declarative @EliSawic
  22. 22. Declarative let array = [0, 1, 2, 3, 4, 5] let evenNumbers = array.filter { $0 % 2 == 0 } @EliSawic
  23. 23. Working with streams @EliSawic
  24. 24. Stream @EliSawic
  25. 25. Manipulating streams @EliSawic
  26. 26. Map @EliSawic
  27. 27. Filter @EliSawic
  28. 28. Aggregating @EliSawic
  29. 29. Skip repeats @EliSawic
  30. 30. Manipulating multiple streams @EliSawic
  31. 31. Combine latest @EliSawic
  32. 32. Zip @EliSawic
  33. 33. Merge @EliSawic
  34. 34. Chaining streams @EliSawic
  35. 35. www.rxmarbles.com @EliSawic
  36. 36. ReactiveCocoa @EliSawic
  37. 37. Thinking in Signals @EliSawic
  38. 38. What is a signal? @EliSawic
  39. 39. This presentation is a signal @EliSawic
  40. 40. Represents events over time @EliSawic
  41. 41. No random access to events @EliSawic
  42. 42. Observe and react @EliSawic
  43. 43. If you don't listen, it's gone @EliSawic
  44. 44. Observing does not trigger side effects @EliSawic
  45. 45. What is event? @EliSawic
  46. 46. Event enum Quality { case Great case Average case Worst } struct Idea { var content: String var quality: Quality } @EliSawic
  47. 47. Non-Terminating • Next @EliSawic
  48. 48. Terminating • Completed • Failed • Interrupted (Reactive Cocoa) @EliSawic
  49. 49. Presentation let (presentation, presentationObserver) = Signal<Idea, NoError>.pipe() let content = "This presentation is a signal" let idea = Idea(content: content, quality: .Great) presentationObserver.send(value: idea) @EliSawic
  50. 50. Observing presentation.observeValues { idea in remember(idea: idea) } presentation.observeCompleted { print("Finally...") } presentationObserver.send(value: idea) presentationObserver.sendCompleted() @EliSawic
  51. 51. Only great ideas let greatIdeas = presentation.filter { $0.quality == .Great } greatIdeas.observeValues { (greatIdea) in remember(idea: greatIdea) } presentationObserver.send(value: idea) presentationObserver.sendCompleted() @EliSawic
  52. 52. Positive listener let greatPresentation = presentation.map { idea -> Idea in var greatIdea = idea greatIdea.quality = .Great return greatIdea } @EliSawic
  53. 53. Count worst ideas let worstIdeas = greatPresentation.filter { $0.quality == .Worst } let numberOfWorstIdeas = worstIdeas.reduce(0) { (sum, idea) -> Int in return sum + 1 } numberOfWorstIdeas.observeValues { (numberOfWorstIdeas) in print("Number of worst ideas: (numberOfWorstIdeas)") } presentationObserver.send(value: idea) presentationObserver.sendCompleted() @EliSawic
  54. 54. Signal's lifetime • Passes any number of Next events • "Dies" when terminating event • Any new observer will receive Interrupted event @EliSawic
  55. 55. Signal producer @EliSawic
  56. 56. Represents a tasks @EliSawic
  57. 57. Creates a signal @EliSawic
  58. 58. Possible side effects @EliSawic
  59. 59. Does not start it's work if not asked @EliSawic
  60. 60. Run presentation func runPresentation() -> SignalProducer<Idea, NoError> { return SignalProducer { observer, _ in observer.send(value: idea1) observer.send(value: idea2) ... observer.sendCompleted() } } @EliSawic
  61. 61. Work with presentation runPresentation().startWithSignal { (signal, _) in signal.observeValues({ idea in print(idea) }) signal.observeCompleted { print("Finally...") } } @EliSawic
  62. 62. Cold vs Hot @EliSawic
  63. 63. Properties @EliSawic
  64. 64. Mutable Property let firstSlide = Slide(number: 1) let slide = MutableProperty<Slide>(firstSlide) slide.producer.startWithNext { (text) in print(text) } slide.value = Slide(number: 2) @EliSawic
  65. 65. Bindings @EliSawic
  66. 66. Binding example let slideNumber = MutableProperty<Int>(0) let (signal, _) = Signal<Slide, NoError>.pipe() slideNumber <~ signal.map { return $0.number } label.reactive.text <~ signal.map { return "Slide number ($0.number)" } @EliSawic
  67. 67. Schedulers @EliSawic
  68. 68. Know where you are signal.observe(on: QueueScheduler.main).observeValues { idea in print("Performing UI updates") } producer.start(on: backgroundQueue).startWithValues { values in print("Starting task") } @EliSawic
  69. 69. Memory Management @EliSawic
  70. 70. Disposables @EliSawic
  71. 71. Free your memory let disposablesBag = CompositeDisposable() disposablesBag += signal.observeValues { value in ... } disposablesBag += producePresentation().startWithValues { (value) in ... } disposablesBag.dispose() @EliSawic
  72. 72. Example @EliSawic
  73. 73. @EliSawic
  74. 74. How does it work? @EliSawic
  75. 75. Is name valid? let isValidName = nameSignal.map { (name) -> Bool in return input.characters.count > 2 } @EliSawic
  76. 76. Is surname valid? let isValidSurname = nameSignal.map { (name) -> Bool in return input.characters.count > 2 } @EliSawic
  77. 77. Is mail valid? let isValidMail = mailSignal.map { (mail) -> Bool in let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,}" let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegEx) return emailTest.evaluateWithObject(mail) } @EliSawic
  78. 78. Combine Latest let formData = combineLatest(isValidName, isValidSurname, isValidMail) @EliSawic
  79. 79. Is form valid? let isValidForm = MutableProperty<Bool>(false) isValidForm <~ formData.map { (isValidName, isValidSurname, isValidMail) -> Bool in return isValidMail && isValidSurname && isValidMail } @EliSawic
  80. 80. Button state let producer = isValidForm.producer.skipRepeats() producer.startWithNext { isValid in updateButtonWith(state: isValid) } @EliSawic
  81. 81. Conclusion @EliSawic
  82. 82. Thank you for your attention! sendCompleted() @EliSawic

×