Slide 1

Slide 1 text

Either, Some or None An introduction to monadic structures and functional programming September 29th, São Paulo, Brazil #monads #functional_programming #category_theory_applied

Slide 2

Slide 2 text

Edson Hilios MSc. Transp. Engineering & BSc. Engineering Software Engineer at _____

Slide 3

Slide 3 text

What I would like to know about monadic structures and monads

Slide 4

Slide 4 text

Why talk about monads? ● Implemented in major modern languages: ● Provides simple ways of express complex computation; ● They are hard to read about because of specific vocabulary;

Slide 5

Slide 5 text

Goals ● A soft theory of Monad ● Monodic structures and operations ● Some common monads ● Real use cases ● Recap

Slide 6

Slide 6 text

WTF is a Monad?

Slide 7

Slide 7 text

If this than that Monads express decisions about how and which conditions a software should execute. It allows you to handle and route different inputs/outputs without repeating yourself.

Slide 8

Slide 8 text

It's a design pattern to describe and manipulate flows of data

Slide 9

Slide 9 text

Useful monad properties ● Composable ● Polymorphic ● Immutable ● Lazily evaluated

Slide 10

Slide 10 text

Interacting with the Monads ● Map ● Filter ● Aggregate ● Group

Slide 11

Slide 11 text

The 3 Monadic laws trait Monoid[A] { // The identity def get[A]: A // The functor def map[B](f: A => B): Monad[B] // The bind def flatMap[B](f: A => Monad[B]): Monad[B] } Scala

Slide 12

Slide 12 text

Show me the Monads

Slide 13

Slide 13 text

The optional pattern val aString: String = "Hello, world!" val len: Int = aString.length Scala

Slide 14

Slide 14 text

The optional pattern val aString: String = null val len: Int = aString.length //=> java.lang.NullPointerException Scala

Slide 15

Slide 15 text

The optional pattern val maybeString: Option[String] = Some("Hello, world!") val maybeLen: Int = maybeString.map(_.length).getOrElse(-1) Scala

Slide 16

Slide 16 text

The optional pattern val maybeString: String? = "Hello, world!" val maybeLen = maybeString?.length ?: -1 Kotlin

Slide 17

Slide 17 text

The optional pattern let maybeString: String? = "Hello, world!" let maybeLen = maybeString.length ?? -1 Swift

Slide 18

Slide 18 text

The continuation monad (some-> (maybe-a-result from-db) (then-do-something) (then-another) (and-finishes)) Clojure Execute if last result is not nil It will return the value or nil Pass the result to the next fn

Slide 19

Slide 19 text

Call me Maybe s::String -> Maybe String s "" = Nothing s x = Just x Haskell

Slide 20

Slide 20 text

The identity monad val query: Option[String] = Option(myNullableOutput) query match { case Some(q) => myTable.filter(_.name == q) case None => myTable.all() } Scala

Slide 21

Slide 21 text

Exception handling val maybeAnOperation: Try[Any] = Try { potentiallyHarmfulOperation() } match { case Success(s: Any) => ??? case Failure(e: ArithmeticException) => ??? case Failure(e: Exception) => ??? } Scala

Slide 22

Slide 22 text

The functor def firstFunctor(x: Any): Try[String] = ??? def secondFunctor(y: String): Try[Int] = ??? def thirdFunctor(z: Int): Try[MyType] = ??? maybeAnException .map(firstFunctor) .map(secondFunctor) .map(thirdFunctor) Try[Any] Try[Try[String]] Try[Try[Try[Int]]] Try[Try[Try[Try[MyType]]]] Scala

Slide 23

Slide 23 text

Bind operations def firstFunctor(x: Any): Try[String] = ??? def secondFunctor(y: String): Try[Int] = ??? def thirdFunctor(z: Int): Try[MyType] = ??? maybeAnException .flatMap(firstFunctor) .flatMap(secondFunctor) .flatMap(thirdFunctor) Try[Any] Try[String] Try[Int] Try[MyType] Scala

Slide 24

Slide 24 text

Either this or that val json: Either[JsError, JsSuccess] = parse("""{"foo": "bar"}""") json match { case JsSuccess(o) => println("OK") case JsError(err) => println(err.list) } Scala

Slide 25

Slide 25 text

Applicative functor def nonEmpty(s: Option[String]): Validated[Invalid, Valid] val isValid = ( nonEmpty("Some string") |@| nonEmpty("") |@| nonEmpty("Other str") |@| nonEmpty(null) ).fold(left => false, rigth => true) Cats

Slide 26

Slide 26 text

Valid Invalid("Cannot be blank") Valid Invalid("Cannot be null") Holomorphism { "1": "Some string", "2": "", "3": "Other str", "4": null } JSON

Slide 27

Slide 27 text

Right or left identity def httpRequest(input: Either[Valid, Invalid]): HttpResponse = input.fold( left => HttpResponse(StatusCodes.BadRequest), right => HttpResponse(StatusCodes.OK)) Scala

Slide 28

Slide 28 text

Future pattern (def eventualString (future (Thread/sleep 1000) "Hello, async!") @eventualString ;; => Returns Hello, async after 1s Clojure

Slide 29

Slide 29 text

Asynchronous operations val eventualLength: Task[String] = Task { Thread.sleep(1000) "Hello, async!" } map { result => result.length } eventualLength.run() // => Eventually returns 13 after 1s Scalaz

Slide 30

Slide 30 text

Sequential or concurrent firstTask .flatMap(secondTask) .flatMap(thirdTask) .run() // => Task[T] Task.gatherUnordered( firstTask, secondTask, thirdTask ).run() // => Task[List(f, s, t)] Scalaz Scalaz

Slide 31

Slide 31 text

Assigning callbacks firstTask.flatMap(secondTask).flatMap(thirdTask) .runAsync { case Success(s) => // Perform side effects case Failure(e) => // Do something on failure } Scalaz

Slide 32

Slide 32 text

It's all about Promises let eventualResponse = new Promise(function() { setTimeout(() => resolve("Hello, world!"), 2000) }) eventualResponse .then(applyFunctor) .then(msg => console.log("Apply side-effects!")) ES2016

Slide 33

Slide 33 text

The observable pattern val observer = new Observer[Any] { def onNext(elem: Any): Future[Ack] = Continue def onError(ex: Throwable): Unit = ex.printStackTrace() def onComplete(): Unit = println("Completed") } Monix

Slide 34

Slide 34 text

Observable operations ● Group by batches or time intervals; ● Fork and merge streams; ● Handle errors and apply retry strategies; ● Delay execution and back-pressure.

Slide 35

Slide 35 text

Becoming reactive Rx.Observable.webSocket('ws://localhost:8000') .retryWhen((errors) => { return Rx.Observable.timer(5000) // retry in 5 secs }) .groupBy((msg) => msg.category) .throttle(1000) // One message per sec and discard the rest .subscribe((msgs) => console.log(msgs)) ES2016

Slide 36

Slide 36 text

Recapping the monads ● Maybe is useful to handle failures scenarios; ● Either for validations and data deserialization; ● Future lets you create asynchronous operations;

Slide 37

Slide 37 text

Monads FTW ● SwiftZ and Runes for Swift ● Kathegory for Kotlin ● Scalaz, Cats and Monix for Scala ● ReactiveX (aka Rx): Scala, C#, C++, Kotlin, Swift and many others

Slide 38

Slide 38 text

Homework ● Reader and Writer Monads ● Monad Transformers ● Free Monad and Free Applicative ● Lenses, Kleisli, and others;

Slide 39

Slide 39 text

Twitter: @hilios Site: http://edson.hilios.com.br Talk: https://speakerdeck.com/hilios GitHub: https://github.com/hilios Thank you!