Skip to content

Commit

Permalink
Add documentation for FlatMap and Bifunctor (#2459)
Browse files Browse the repository at this point in the history
* Add documentation for FlatMap and Bifunctor

* Fix page title
  • Loading branch information
asoltysik authored and kailuowang committed Sep 25, 2018
1 parent 04e8fcf commit 8f1aafe
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 0 deletions.
52 changes: 52 additions & 0 deletions docs/src/main/tut/typeclasses/bifunctor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
layout: docs
title: "Bifunctor"
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`.
23 changes: 23 additions & 0 deletions docs/src/main/tut/typeclasses/monad.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

0 comments on commit 8f1aafe

Please sign in to comment.