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.
About me
Eliasz Sawicki
Blog: www.eliaszsawicki.com
Twitter: @EliSawic
@EliSawic
Introduction to
Functional Reactive
Programming
@EliSawic
Agenda
• What is Functional Reactive Programming?
• Let's take a look at ReactiveCocoa
• Working with streams
• Real life ...
Functional Reactive
Programming
@EliSawic
Wikipedia
Functional reactive programming (FRP) is a programming
paradigm for reactive programming (asynchronous dataflow
p...
Reactive
Programming
@EliSawic
Asynchronous
Dataflow
@EliSawic
Reacting to state
changes
@EliSawic
Functional
Programming
@EliSawic
Immutable
@EliSawic
assert(f(x) == f(x))
@EliSawic
A person
class Person {
let name: String
let phoneNumber: String
init(name: String, phoneNumber: String) {
self.name = nam...
Mutable
let mobilePhone = MobilePhone()
let john = Person(name: "John", phoneNumber: "123456789")
func makeAPhoneCall(devi...
Immutable
let mobilePhone = MobilePhone()
let john = Person(name: "John", phoneNumber: "123456789")
func makeAPhoneCall(de...
Stateless
@EliSawic
Stateful
var value = 0
func increment() -> Int {
value += 1
return value
}
@EliSawic
Stateless
func increment(value: Int) -> Int {
return value + 1
}
@EliSawic
Functional Reactive
Programming
@EliSawic
Imperative
vs
Declarative
@EliSawic
Imperative
@EliSawic
Imperative
let array = [0, 1, 2, 3, 4, 5]
var evenNumbers = [Int]()
for element in array {
if element % 2 == 0 {
evenNumbe...
Declarative
@EliSawic
Declarative
let array = [0, 1, 2, 3, 4, 5]
let evenNumbers = array.filter { $0 % 2 == 0 }
@EliSawic
ReactiveCocoa
@EliSawic
Event streams
@EliSawic
Event Stream
@EliSawic
Event
@EliSawic
Non-Terminating
• Next
@EliSawic
Terminating
• Completed
• Failed
• Interrupted (Reactive Cocoa)
@EliSawic
Signal
@EliSawic
Events over time
@EliSawic
No side effects
@EliSawic
No random access to
events
@EliSawic
Must be observed in
order to access it's
events
@EliSawic
Hot
@EliSawic
Signal's lifetime
• Passes any number of Next events
• "Dies" when terminating event
• Any new observer will receive Inter...
Observing
let someWork = Signal<Int, NoError> { observer in
observer.sendNext(1)
observer.sendNext(2)
....
observer.sendNe...
Pipe
@EliSawic
Pipe
let (signal, observer) = Signal<String, NoError>.pipe()
signal.observeNext({ text in
print(text)
})
signal.observeCom...
SignalProducer
@EliSawic
Represents tasks
@EliSawic
Creates signal
@EliSawic
Possible side effects
@EliSawic
Does not start it's
work if not started
@EliSawic
Cold
@EliSawic
Using Signal Producer
let producer = SignalProducer<String, NSError> { (observer, composite) in
observer.sendNext("In Prog...
Cold vs Hot
@EliSawic
Properties
@EliSawic
MutableProperty
let name = MutableProperty("Bob")
name.producer.startWithNext { (text) in
print(text)
}
name.value = "Lisa...
Bindings
@EliSawic
Basic binding
let property = MutableProperty<String>("")
let (signal, _) = Signal<String, NoError>.pipe()
property <~ sign...
Schedulers
@EliSawic
Memory Management
@EliSawic
Disposables
@EliSawic
Manipulating signals
@EliSawic
Map
@EliSawic
Filter
@EliSawic
Aggregating
@EliSawic
Skip repeats
@EliSawic
Manipulating
multiple signals
@EliSawic
Combine latest
@EliSawic
Zip
@EliSawic
Merge
@EliSawic
Chaining operators
@EliSawic
Chain them all!
let newSignalX = signalX.skipRepeats()
.filter { x > 2 }
.map { x * 10 }
let newSignalY = signalY.filter {...
Example
@EliSawic
@EliSawic
@EliSawic
@EliSawic
@EliSawic
@EliSawic
How does it work?
@EliSawic
Is name valid?
let isValidName = nameSignal.map { (name) -> Bool in
return input.characters.count > 2
}
@EliSawic
Is mail valid?
let isValidMail = mailSignal.map { (mail) -> Bool in
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+.[A-...
Combine Latest
let formData = combineLatest(isValidName,
isValidSurname,
isValidMail)
@EliSawic
Is form valid?
disposables += isFormValid <~ formData.map {
(isValidName, isValidSurname, isValidMail) -> Bool in
return i...
Button state
let producer = isFormValid.producer.skipRepeats()
disposables += producer.startWithNext {[unowned self] (isVa...
Conclusion
@EliSawic
Thank you for your
attention!
@EliSawic
Upcoming SlideShare
Loading in …5
×

Introduction to Functional Reactive Programming

169 views

Published on

Introduction to functional reactive programming. ReactiveCocoa is used as example FRP inspired framework.

Published in: Mobile
  • Be the first to comment

Introduction to Functional Reactive Programming

  1. 1. About me Eliasz Sawicki Blog: www.eliaszsawicki.com Twitter: @EliSawic @EliSawic
  2. 2. Introduction to Functional Reactive Programming @EliSawic
  3. 3. Agenda • What is Functional Reactive Programming? • Let's take a look at ReactiveCocoa • Working with streams • Real life example • Conclusion @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. Functional Reactive Programming @EliSawic
  19. 19. Imperative vs Declarative @EliSawic
  20. 20. Imperative @EliSawic
  21. 21. Imperative let array = [0, 1, 2, 3, 4, 5] var evenNumbers = [Int]() for element in array { if element % 2 == 0 { evenNumbers.append(element) } } @EliSawic
  22. 22. Declarative @EliSawic
  23. 23. Declarative let array = [0, 1, 2, 3, 4, 5] let evenNumbers = array.filter { $0 % 2 == 0 } @EliSawic
  24. 24. ReactiveCocoa @EliSawic
  25. 25. Event streams @EliSawic
  26. 26. Event Stream @EliSawic
  27. 27. Event @EliSawic
  28. 28. Non-Terminating • Next @EliSawic
  29. 29. Terminating • Completed • Failed • Interrupted (Reactive Cocoa) @EliSawic
  30. 30. Signal @EliSawic
  31. 31. Events over time @EliSawic
  32. 32. No side effects @EliSawic
  33. 33. No random access to events @EliSawic
  34. 34. Must be observed in order to access it's events @EliSawic
  35. 35. Hot @EliSawic
  36. 36. Signal's lifetime • Passes any number of Next events • "Dies" when terminating event • Any new observer will receive Interrupted event @EliSawic
  37. 37. Observing let someWork = Signal<Int, NoError> { observer in observer.sendNext(1) observer.sendNext(2) .... observer.sendNext(1000000) observer.sendCompleted() } signal.observe { (event) in print(event) } signal.observeNext { (value) in print(value) } signal.observeCompleted { print("Completed") } @EliSawic
  38. 38. Pipe @EliSawic
  39. 39. Pipe let (signal, observer) = Signal<String, NoError>.pipe() signal.observeNext({ text in print(text) }) signal.observeCompleted({ print("Test completed") }) observer.sendNext("It's a test") // It's a test observer.sendCompleted() // Test completed @EliSawic
  40. 40. SignalProducer @EliSawic
  41. 41. Represents tasks @EliSawic
  42. 42. Creates signal @EliSawic
  43. 43. Possible side effects @EliSawic
  44. 44. Does not start it's work if not started @EliSawic
  45. 45. Cold @EliSawic
  46. 46. Using Signal Producer let producer = SignalProducer<String, NSError> { (observer, composite) in observer.sendNext("In Progress...") // ...... observer.sendCompleted() } producer.startWithSignal { (signal, _) in signal.observeNext({ (text) in print(text) // In Progress... }) signal.observeCompleted({ print("Test completed") // Test completed }) } @EliSawic
  47. 47. Cold vs Hot @EliSawic
  48. 48. Properties @EliSawic
  49. 49. MutableProperty let name = MutableProperty("Bob") name.producer.startWithNext { (text) in print(text) } name.value = "Lisa" @EliSawic
  50. 50. Bindings @EliSawic
  51. 51. Basic binding let property = MutableProperty<String>("") let (signal, _) = Signal<String, NoError>.pipe() property <~ signal @EliSawic
  52. 52. Schedulers @EliSawic
  53. 53. Memory Management @EliSawic
  54. 54. Disposables @EliSawic
  55. 55. Manipulating signals @EliSawic
  56. 56. Map @EliSawic
  57. 57. Filter @EliSawic
  58. 58. Aggregating @EliSawic
  59. 59. Skip repeats @EliSawic
  60. 60. Manipulating multiple signals @EliSawic
  61. 61. Combine latest @EliSawic
  62. 62. Zip @EliSawic
  63. 63. Merge @EliSawic
  64. 64. Chaining operators @EliSawic
  65. 65. Chain them all! let newSignalX = signalX.skipRepeats() .filter { x > 2 } .map { x * 10 } let newSignalY = signalY.filter { x > 10 } let combined = combineLatest(newSignalX, newSignalY) combined.observeNext { xValue, yValue in print("Update: (xValue) : (yValue)") } @EliSawic
  66. 66. Example @EliSawic
  67. 67. @EliSawic
  68. 68. @EliSawic
  69. 69. @EliSawic
  70. 70. @EliSawic
  71. 71. @EliSawic
  72. 72. How does it work? @EliSawic
  73. 73. Is name valid? let isValidName = nameSignal.map { (name) -> Bool in return input.characters.count > 2 } @EliSawic
  74. 74. 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
  75. 75. Combine Latest let formData = combineLatest(isValidName, isValidSurname, isValidMail) @EliSawic
  76. 76. Is form valid? disposables += isFormValid <~ formData.map { (isValidName, isValidSurname, isValidMail) -> Bool in return isValidMail && isValidSurname && isValidMail } @EliSawic
  77. 77. Button state let producer = isFormValid.producer.skipRepeats() disposables += producer.startWithNext {[unowned self] (isValid) in self.updateAcceptButtonWithState(isValid) } @EliSawic
  78. 78. Conclusion @EliSawic
  79. 79. Thank you for your attention! @EliSawic

×