Instantly share code, notes, and snippets.

# arosien/20200519.md Last active May 20, 2020

"Functional Programming Demystification" @ Scala at the Sea, 19 May 2020

# Functional Programming Demystification

Functional programming is full of Fancy Words™. Let's collect a list of them to demystify together. Adam will facilitate with live-coding, and will also try to make good jokes.

Here's some terms to bootstrap us: effect, free monad, functor, property-based testing, refinement type, stream, etc.

We will have plenty of time for Q&A during this session.

## "Essential Effects" Course Now Available!

https://www.inner-product.com/services/training/essential-effects/

How to safely create, compose, and execute effectful Scala programs using the Typelevel cats-effect library.

## TODO

The audience suggested starting with functor, monad, and effect, so here we go!

## Functor

• captures the notion of `map`: `List`, `Option`, `Future` all have `map`
• see worksheet for code

## Aside: Typeclasses and Their Laws

• typeclass: interface + implementations for various types

"How do we know an implementation of a typeclass is correct?"

For `Functor.map`, how do we know it works? Laws!

Laws for `Functor`:

• identity law: `map(identity)` = `identity`
• "doing nothing should really do nothing"
• composition: `fa.map(f).map(g) == fa.map(f andThen g)`
• "mapping twice should be the same as mapping once with composed transformations"

• captures the notion of `flatMap` (and `pure`)
• see worksheet for code

## Effect

What is an effect? Is it different than a side-effect, which we know is "bad" or "dangerous"?

Examples:

• "passing state after the computation" == state effect, e.g., incrementing a counter when executing something; see worksheet
• "`NullPointerException` effect" == `Option`
• "Error" effect == `Either[L, R]`
• Dependency Injection == `Reader`
• println(), a.k.a., logging == `Writer`
• asynchronous computation == `scala.concurrent.Future`? Future is not referentially transparent! This can bite you or your friend.
• `cats.effect.IO`: do anything, even side-effects!

BIG IDEAS in effects:

• replace side-effects with more structure, more laws, immutability, etc., to make them safe
• the effect is apparent in the type signature; this lets us "see" that something is going on, as opposed to side-effects
• we separate the description of what we want to do from execution of that description

## Resources

 1 + 13 // // Functor // List(1, 2, 3).map(_ + 1) Option(1).map(_.toString) // typeclass trait Functor[F[_]] { def map[A, B](fa: F[A])(f: A => B): F[B] def void[A](fa: F[A]): F[Unit] = map(fa)(a => ()) } // laws class FunctorLaws[F[_]](f: Functor[F]) { def identityLaw[A](fa: F[A]) = f.map(fa)(identity) == fa def composition[A, B, C](fa: F[A], a2b: A => B, b2c: B => C) = f.map(f.map(fa)(a2b))(b2c) == f.map(fa)(a2b andThen b2c) } // typeclass instances implicit val listFunctor: Functor[List] = new Functor[List] { def map[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f) } implicit val optionFunctor: Functor[Option] = new Functor[Option] { def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f) } // val intFunctor: Functor[Int] = ??? // the idea: _abstract_ over F containers that you can map over def addOne[F[_]](is: F[Int])(implicit functor: Functor[F]): F[Int] = functor.map(is)(_ + 1) addOne(List(1, 2, 3)) addOne(Option(1)) // // Monad // trait Monad[F[_]] { def pure[A](a: A): F[A] def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] } // // Effects // // example: replace mutable counter with immutable "state" effect var numAddOne = 0 // pass initial counter state in, next counter state out, along with the actual computation def addOne2[F[_]](is: F[Int])(count: Long)(implicit functor: Functor[F]): F[(Long, Int)] = functor.map(is)(i => (count + 1, i + 1)) def addOne2[F[_], S](is: F[Int])(state: S, f: S => S)(implicit functor: Functor[F]): F[(S, Int)] = functor.map(is)(i => (f(state), i + 1)) // eventually you can refactor this ^^^ to be some datatype like State or StateT that couples the state change with the actual computation case class StateT[F[_], S, A](f: S => F[(S, A)])