From ae72122c5e178ff2b0cd2c2d870d02e55090312e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20So=C5=82tysik?= Date: Mon, 3 Sep 2018 18:32:49 +0200 Subject: [PATCH 1/2] Add documentation for FlatMap and Bifunctor --- docs/src/main/tut/typeclasses/bifunctor.md | 52 ++++++++++++++++++++++ docs/src/main/tut/typeclasses/monad.md | 23 ++++++++++ 2 files changed, 75 insertions(+) create mode 100644 docs/src/main/tut/typeclasses/bifunctor.md diff --git a/docs/src/main/tut/typeclasses/bifunctor.md b/docs/src/main/tut/typeclasses/bifunctor.md new file mode 100644 index 0000000000..d841ffdd2f --- /dev/null +++ b/docs/src/main/tut/typeclasses/bifunctor.md @@ -0,0 +1,52 @@ +--- +layout: docs +title: "Functor" +section: "typeclasses" +source: "core/src/main/scala/cats/Bifunctor.scala" +scaladoc: "#cats.Bifunctor" +--- +# Bifunctor + +`Bifunctor` takes two type parameters instead of one, and is a functor in both +of these parameters. It defines a function `bimap`, which allows for mapping over both +arguments at the same time. Its signature is as follows: + +```scala +def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D] +``` + +## Either as a Bifunctor + +Probably the most widely used Bifunctor instance is the Either data type. + +Say you have a value that is either an error or a `ZonedDateTime` instance. +You also want to react to both possibilities - if there was a failure, you want to +convert it to your own `DomainError`, and if the result was a success, you want to +convert it to an UNIX timestamp. + +```tut:silent +import cats._ +import cats.implicits._ +import java.time._ + +case class DomainError(message: String) + +def dateTimeFromUser: Either[Throwable, ZonedDateTime] = + Right(ZonedDateTime.now()) // Example definition +``` + +```tut:book +dateTimeFromUser.bimap( + error => DomainError(error.getMessage), + dateTime => dateTime.toEpochSecond +) +``` + +`Bifunctor` also defines a convenience function called `leftMap`, which is defined as follows: + +```scala +def leftMap[A, B, C](fab: F[A, B])(f: A => C): F[C, B] = bimap(fab)(f, identity) +``` + +There is no `rightMap` however - use `map` instead. The reasoning behind this is that in Cats, the instances of +`Bifunctor` are also mostly instances of `Functor`, as it is the case with `Either`. diff --git a/docs/src/main/tut/typeclasses/monad.md b/docs/src/main/tut/typeclasses/monad.md index 57b41343f9..c69ee805fe 100644 --- a/docs/src/main/tut/typeclasses/monad.md +++ b/docs/src/main/tut/typeclasses/monad.md @@ -159,3 +159,26 @@ implicit def optionTMonad[F[_]](implicit F : Monad[F]) = { This sort of construction is called a monad transformer. Cats has an [`OptionT`](optiont.html) monad transformer, which adds a lot of useful functions to the simple implementation above. + +## FlatMap - a weakened Monad +A closely related type class is `FlatMap` which is identical to `Monad`, minus the `pure` +method. Indeed in Cats `Monad` is a subclass of `FlatMap` (from which it gets `flatMap`) +and `Applicative` (from which it gets `pure`). + +```scala +trait FlatMap[F[_]] extends Apply[F] { + def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B] +} + +trait Monad[F[_]] extends FlatMap[F] with Applicative[F] +``` + +The laws for `FlatMap` are just the laws of `Monad` that don't mention `pure`. + +One of the motivations for `FlatMap`'s existence is that some types have `FlatMap` instances but not +`Monad` - one example is `Map[K, ?]`. Consider the behavior of `pure` for `Map[K, A]`. Given +a value of type `A`, we need to associate some arbitrary `K` to it but we have no way of doing that. + +However, given existing `Map[K, A]` and `Map[K, B]` (or `Map[K, A => B]`), it is straightforward to +pair up (or apply functions to) values with the same key. Hence `Map[K, ?]` has an `FlatMap` instance. + From 5b46d5019891607e48fafa6b4f74eb9b0478019f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20So=C5=82tysik?= Date: Mon, 3 Sep 2018 18:39:07 +0200 Subject: [PATCH 2/2] Fix page title --- docs/src/main/tut/typeclasses/bifunctor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/tut/typeclasses/bifunctor.md b/docs/src/main/tut/typeclasses/bifunctor.md index d841ffdd2f..4f3bc24083 100644 --- a/docs/src/main/tut/typeclasses/bifunctor.md +++ b/docs/src/main/tut/typeclasses/bifunctor.md @@ -1,6 +1,6 @@ --- layout: docs -title: "Functor" +title: "Bifunctor" section: "typeclasses" source: "core/src/main/scala/cats/Bifunctor.scala" scaladoc: "#cats.Bifunctor"