Advertisement

Introduction To Functional Reactive Programming Poznan

Nov. 20, 2016
Advertisement

More Related Content

Advertisement

Introduction To Functional Reactive Programming Poznan

  1. Introduction to Functional Reactive Programming @EliSawic
  2. About me Eliasz Sawicki Blog: www.eliaszsawicki.com Twitter: @EliSawic @EliSawic
  3. Agenda • What is functional reactive programming? • Working with streams • ReactiveCocoa - Thinking in signals • Example @EliSawic
  4. Functional Reactive Programming @EliSawic
  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. Reactive Programming @EliSawic
  7. Asynchronous Dataflow @EliSawic
  8. Reacting to state changes @EliSawic
  9. Functional Programming @EliSawic
  10. Immutable @EliSawic
  11. assert(f(x) == f(x)) @EliSawic
  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. 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. 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. Stateless @EliSawic
  16. Stateful var value = 0 func increment() -> Int { value += 1 return value } @EliSawic
  17. Stateless func increment(value: Int) -> Int { return value + 1 } @EliSawic
  18. Imperative vs Declarative @EliSawic
  19. Imperative @EliSawic
  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. Declarative @EliSawic
  22. Declarative let array = [0, 1, 2, 3, 4, 5] let evenNumbers = array.filter { $0 % 2 == 0 } @EliSawic
  23. Working with streams @EliSawic
  24. Stream @EliSawic
  25. Manipulating streams @EliSawic
  26. Map @EliSawic
  27. Filter @EliSawic
  28. Aggregating @EliSawic
  29. Skip repeats @EliSawic
  30. Manipulating multiple streams @EliSawic
  31. Combine latest @EliSawic
  32. Zip @EliSawic
  33. Merge @EliSawic
  34. Chaining streams @EliSawic
  35. www.rxmarbles.com @EliSawic
  36. ReactiveCocoa @EliSawic
  37. Thinking in Signals @EliSawic
  38. What is a signal? @EliSawic
  39. This presentation is a signal @EliSawic
  40. Represents events over time @EliSawic
  41. No random access to events @EliSawic
  42. Observe and react @EliSawic
  43. If you don't listen, it's gone @EliSawic
  44. Observing does not trigger side effects @EliSawic
  45. What is event? @EliSawic
  46. Event enum Quality { case Great case Average case Worst } struct Idea { var content: String var quality: Quality } @EliSawic
  47. Non-Terminating • Next @EliSawic
  48. Terminating • Completed • Failed • Interrupted (Reactive Cocoa) @EliSawic
  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. Observing presentation.observeValues { idea in remember(idea: idea) } presentation.observeCompleted { print("Finally...") } presentationObserver.send(value: idea) presentationObserver.sendCompleted() @EliSawic
  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. Positive listener let greatPresentation = presentation.map { idea -> Idea in var greatIdea = idea greatIdea.quality = .Great return greatIdea } @EliSawic
  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. Signal's lifetime • Passes any number of Next events • "Dies" when terminating event • Any new observer will receive Interrupted event @EliSawic
  55. Signal producer @EliSawic
  56. Represents a tasks @EliSawic
  57. Creates a signal @EliSawic
  58. Possible side effects @EliSawic
  59. Does not start it's work if not asked @EliSawic
  60. Run presentation func runPresentation() -> SignalProducer<Idea, NoError> { return SignalProducer { observer, _ in observer.send(value: idea1) observer.send(value: idea2) ... observer.sendCompleted() } } @EliSawic
  61. Work with presentation runPresentation().startWithSignal { (signal, _) in signal.observeValues({ idea in print(idea) }) signal.observeCompleted { print("Finally...") } } @EliSawic
  62. Cold vs Hot @EliSawic
  63. Properties @EliSawic
  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. Bindings @EliSawic
  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. Schedulers @EliSawic
  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. Memory Management @EliSawic
  70. Disposables @EliSawic
  71. Free your memory let disposablesBag = CompositeDisposable() disposablesBag += signal.observeValues { value in ... } disposablesBag += producePresentation().startWithValues { (value) in ... } disposablesBag.dispose() @EliSawic
  72. Example @EliSawic
  73. @EliSawic
  74. How does it work? @EliSawic
  75. Is name valid? let isValidName = nameSignal.map { (name) -> Bool in return input.characters.count > 2 } @EliSawic
  76. Is surname valid? let isValidSurname = nameSignal.map { (name) -> Bool in return input.characters.count > 2 } @EliSawic
  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. Combine Latest let formData = combineLatest(isValidName, isValidSurname, isValidMail) @EliSawic
  79. Is form valid? let isValidForm = MutableProperty<Bool>(false) isValidForm <~ formData.map { (isValidName, isValidSurname, isValidMail) -> Bool in return isValidMail && isValidSurname && isValidMail } @EliSawic
  80. Button state let producer = isValidForm.producer.skipRepeats() producer.startWithNext { isValid in updateButtonWith(state: isValid) } @EliSawic
  81. Conclusion @EliSawic
  82. Thank you for your attention! sendCompleted() @EliSawic
Advertisement