Skip to content

Instantly share code, notes, and snippets.

View wennergr's full-sized avatar

Tobias Wennergren wennergr

View GitHub Profile
val IOoOption = compose[IO, Option]
// Using cats:
// val IOoOption = Applicative[IO].compose[Option]
val user: IO[Option[User]] =
IOoOption.map2(getName2(userId), getAddress2(userId))(User.apply)
@wennergr
wennergr / ex.scala
Last active March 28, 2018 15:31
Applicative functor composition
import cats._, cats.implicits._, cats.effect.IO
// No details about any specific applicative functor
def compose[F[_]: Applicative, G[_]: Applicative](): Applicative[Lambda[l => F[G[l]]]] = {
val AF = Applicative[F]
val AG = Applicative[G]
new Applicative[Lambda[l => F[G[l]]]] {
override def pure[A](a: A): F[G[A]] = AF.pure(AG.pure(a))
override def ap[A, B](ff: F[G[A => B]])(fa: F[G[A]]): F[G[B]] =
@wennergr
wennergr / ex.scala
Last active March 28, 2018 14:53
Ap function
import cats._, cats.implicits._, cats.effect.IO
// Adds two numbers together (curried)
val add = (x: Int) => (y: Int) => x + y
// Example using the ap function for list
val A1: List[Int => Int] = List(1,2).map(add) // map comes from the functor typeclass
val result1: List[Int] = Applicative[List].ap(A1)(List(4,5)) // List[Int](5,6,6,7)
// Example using the ap function for IO
@wennergr
wennergr / ex.scala
Last active March 28, 2018 17:15
IO of Option
// Old version
// def getName(id: Long): IO[Name] = /* Call third party API */
// def getAddress(id: Long): IO[Address] = /* Call third party API */
// The return type is now IO[Option[_]]
def getName(id: Long): IO[Option[Name]] = /* Call third party API */
def getAddress(id: Long): IO[Option[Address]] = /* Call third party API */
val userId = 100L
@wennergr
wennergr / ex.scala
Last active March 26, 2018 15:56
Real world applicative functor version
// Applicative functor version
val user: IO[User] = Applicative[IO].map2(getName(userId), getAddress(userId))(User.apply)
// Alterntive version with mapN on tupleN
val user: IO[User] = (getName(userId), getAddress(userId)).mapN(User.apply)
@wennergr
wennergr / ex.scala
Last active March 21, 2018 15:42
Real world monad version
val user: IO[User] = for {
name <- getName(userId)
address <- getAddress(userId)
} yield User(name, address)
@wennergr
wennergr / ex.scala
Last active March 21, 2018 15:48
Real world example
import cats._, cats.implicits._, cats.effect.IO
case class Name(firstName: String, lastName: String)
case class Address(street: String, zip: String, state: String)
case class User(name: Name, address: Address)
def getName(id: Long): IO[Name] = /* Call third party API */
def getAddress(id: Long): IO[Address] = /* Call third party API */
val userId = 100L
// Monad version
for {
firstName <- Some("Bob")
lastName <- Some("Axel")
} yield firstname + " " + lastName // Some("Bob Axel")
// Applicative functor version
Applicative[Option].map2(Some("Bob"), Some("Axel"))((a,b) => a + " " + b) // Some("Bob Axel")
@wennergr
wennergr / ex.scala
Last active March 21, 2018 15:29
Applicative with map2
trait Applicative[F[_]] extends Functor[F] {
def pure[A](x: A): F[A]
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z] =
ap(map(fa)(a => (b: B) => f(a,b)))(fb)
}
@wennergr
wennergr / ex.scala
Last active March 21, 2018 15:29
Applicative defintion
trait Applicative[F[_]] extends Functor[F] {
def pure[A](x: A): F[A]
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
}