79
About me Eliasz Sawicki Blog: www.eliaszsawicki.com Twitter: @EliSawic @EliSawic

Introduction to Functional Reactive Programming

Embed Size (px)

Citation preview

Page 1: Introduction to Functional Reactive Programming

About me

Eliasz SawickiBlog: www.eliaszsawicki.comTwitter: @EliSawic

@EliSawic

Page 2: Introduction to Functional Reactive Programming

Introduction to Functional Reactive

Programming

@EliSawic

Page 3: Introduction to Functional Reactive Programming

Agenda• What is Functional Reactive Programming?

• Let's take a look at ReactiveCocoa

• Working with streams

• Real life example

• Conclusion

@EliSawic

Page 4: Introduction to Functional Reactive Programming

Functional Reactive Programming

@EliSawic

Page 5: Introduction to Functional Reactive Programming

WikipediaFunctional 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

Page 6: Introduction to Functional Reactive Programming

Reactive Programming

@EliSawic

Page 7: Introduction to Functional Reactive Programming

Asynchronous Dataflow

@EliSawic

Page 8: Introduction to Functional Reactive Programming

Reacting to state changes

@EliSawic

Page 9: Introduction to Functional Reactive Programming

Functional Programming

@EliSawic

Page 10: Introduction to Functional Reactive Programming

Immutable

@EliSawic

Page 11: Introduction to Functional Reactive Programming

assert(f(x) == f(x))

@EliSawic

Page 12: Introduction to Functional Reactive Programming

A personclass 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

Page 13: Introduction to Functional Reactive Programming

Mutablelet 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") // truemakeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // falsemakeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // false

@EliSawic

Page 14: Introduction to Functional Reactive Programming

Immutablelet 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") // truemakeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // truemakeAPhoneCall(device: mobilePhone, person: john, countryCode: "+48") // true

@EliSawic

Page 15: Introduction to Functional Reactive Programming

Stateless

@EliSawic

Page 16: Introduction to Functional Reactive Programming

Statefulvar value = 0

func increment() -> Int { value += 1 return value}

@EliSawic

Page 17: Introduction to Functional Reactive Programming

Statelessfunc increment(value: Int) -> Int { return value + 1}

@EliSawic

Page 18: Introduction to Functional Reactive Programming

Functional Reactive Programming

@EliSawic

Page 19: Introduction to Functional Reactive Programming

Imperative vs

Declarative

@EliSawic

Page 20: Introduction to Functional Reactive Programming

Imperative

@EliSawic

Page 21: Introduction to Functional Reactive Programming

Imperativelet array = [0, 1, 2, 3, 4, 5]var evenNumbers = [Int]()for element in array { if element % 2 == 0 { evenNumbers.append(element) }}

@EliSawic

Page 22: Introduction to Functional Reactive Programming

Declarative

@EliSawic

Page 23: Introduction to Functional Reactive Programming

Declarativelet array = [0, 1, 2, 3, 4, 5]let evenNumbers = array.filter { $0 % 2 == 0 }

@EliSawic

Page 24: Introduction to Functional Reactive Programming

ReactiveCocoa

@EliSawic

Page 25: Introduction to Functional Reactive Programming

Event streams

@EliSawic

Page 26: Introduction to Functional Reactive Programming

Event Stream

@EliSawic

Page 27: Introduction to Functional Reactive Programming

Event

@EliSawic

Page 28: Introduction to Functional Reactive Programming

Non-Terminating• Next

@EliSawic

Page 29: Introduction to Functional Reactive Programming

Terminating

• Completed

• Failed

• Interrupted (Reactive Cocoa)

@EliSawic

Page 30: Introduction to Functional Reactive Programming

Signal

@EliSawic

Page 31: Introduction to Functional Reactive Programming

Events over time

@EliSawic

Page 32: Introduction to Functional Reactive Programming

No side effects

@EliSawic

Page 33: Introduction to Functional Reactive Programming

No random access to events

@EliSawic

Page 34: Introduction to Functional Reactive Programming

Must be observed in order to access it's

events

@EliSawic

Page 35: Introduction to Functional Reactive Programming

Hot

@EliSawic

Page 36: Introduction to Functional Reactive Programming

Signal's lifetime• Passes any number of Next events

• "Dies" when terminating event

• Any new observer will receive Interrupted event

@EliSawic

Page 37: Introduction to Functional Reactive Programming

Observinglet 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

Page 38: Introduction to Functional Reactive Programming

Pipe

@EliSawic

Page 39: Introduction to Functional Reactive Programming

Pipelet (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 testobserver.sendCompleted() // Test completed

@EliSawic

Page 40: Introduction to Functional Reactive Programming

SignalProducer

@EliSawic

Page 41: Introduction to Functional Reactive Programming

Represents tasks

@EliSawic

Page 42: Introduction to Functional Reactive Programming

Creates signal

@EliSawic

Page 43: Introduction to Functional Reactive Programming

Possible side effects

@EliSawic

Page 44: Introduction to Functional Reactive Programming

Does not start it's work if not started

@EliSawic

Page 45: Introduction to Functional Reactive Programming

Cold

@EliSawic

Page 46: Introduction to Functional Reactive Programming

Using Signal Producerlet 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

Page 47: Introduction to Functional Reactive Programming

Cold vs Hot

@EliSawic

Page 48: Introduction to Functional Reactive Programming

Properties

@EliSawic

Page 49: Introduction to Functional Reactive Programming

MutablePropertylet name = MutableProperty("Bob")

name.producer.startWithNext { (text) in print(text)}

name.value = "Lisa"

@EliSawic

Page 50: Introduction to Functional Reactive Programming

Bindings

@EliSawic

Page 51: Introduction to Functional Reactive Programming

Basic bindinglet property = MutableProperty<String>("")let (signal, _) = Signal<String, NoError>.pipe()property <~ signal

@EliSawic

Page 52: Introduction to Functional Reactive Programming

Schedulers

@EliSawic

Page 53: Introduction to Functional Reactive Programming

Memory Management

@EliSawic

Page 54: Introduction to Functional Reactive Programming

Disposables

@EliSawic

Page 55: Introduction to Functional Reactive Programming

Manipulating signals

@EliSawic

Page 56: Introduction to Functional Reactive Programming

Map

@EliSawic

Page 57: Introduction to Functional Reactive Programming

Filter

@EliSawic

Page 58: Introduction to Functional Reactive Programming

Aggregating

@EliSawic

Page 59: Introduction to Functional Reactive Programming

Skip repeats

@EliSawic

Page 60: Introduction to Functional Reactive Programming

Manipulating multiple signals

@EliSawic

Page 61: Introduction to Functional Reactive Programming

Combine latest

@EliSawic

Page 62: Introduction to Functional Reactive Programming

Zip

@EliSawic

Page 63: Introduction to Functional Reactive Programming

Merge

@EliSawic

Page 64: Introduction to Functional Reactive Programming

Chaining operators

@EliSawic

Page 65: Introduction to Functional Reactive Programming

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

Page 66: Introduction to Functional Reactive Programming

Example

@EliSawic

Page 67: Introduction to Functional Reactive Programming

@EliSawic

Page 68: Introduction to Functional Reactive Programming

@EliSawic

Page 69: Introduction to Functional Reactive Programming

@EliSawic

Page 70: Introduction to Functional Reactive Programming

@EliSawic

Page 71: Introduction to Functional Reactive Programming

@EliSawic

Page 72: Introduction to Functional Reactive Programming

How does it work?

@EliSawic

Page 73: Introduction to Functional Reactive Programming

Is name valid?let isValidName = nameSignal.map { (name) -> Bool in return input.characters.count > 2}

@EliSawic

Page 74: Introduction to Functional Reactive Programming

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

Page 75: Introduction to Functional Reactive Programming

Combine Latestlet formData = combineLatest(isValidName, isValidSurname, isValidMail)

@EliSawic

Page 76: Introduction to Functional Reactive Programming

Is form valid?disposables += isFormValid <~ formData.map { (isValidName, isValidSurname, isValidMail) -> Bool in return isValidMail && isValidSurname && isValidMail}

@EliSawic

Page 77: Introduction to Functional Reactive Programming

Button statelet producer = isFormValid.producer.skipRepeats()disposables += producer.startWithNext {[unowned self] (isValid) in self.updateAcceptButtonWithState(isValid)}

@EliSawic

Page 78: Introduction to Functional Reactive Programming

Conclusion

@EliSawic

Page 79: Introduction to Functional Reactive Programming

Thank you for your attention!

@EliSawic