Skip to content

Commit

Permalink
Merge pull request #667 from lambdista/optiont-liftf
Browse files Browse the repository at this point in the history
add OptionT.liftF and update related docs and tests. Close issue #659
  • Loading branch information
non committed Nov 17, 2015
2 parents 1ca7970 + 4383dcc commit 246512e
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This file lists the people whose contributions have made Cats
possible:

* Adelbert Chang
* Alessandro Lacava
* Alissa Pajer
* Alistair Johnson
* Amir Mohammad Saied
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ object OptionT extends OptionTInstances {
def apply[A](value: Option[A])(implicit F: Applicative[F]): OptionT[F, A] =
OptionT(F.pure(value))
}

/**
* Lifts the `F[A]` Functor into an `OptionT[F, A]`.
*
*/
def liftF[F[_], A](fa: F[A])(implicit F: Functor[F]): OptionT[F, A] = OptionT(F.map(fa)(Some(_)))
}

private[data] sealed trait OptionTInstances1 {
Expand Down
21 changes: 21 additions & 0 deletions docs/src/main/tut/optiont.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ val noWelcome: OptionT[Future, String] = customGreetingT.filterNot(_.contains("w
val withFallback: Future[String] = customGreetingT.getOrElse("hello, there!")
```

## From `Option[A]` and/or `F[A]` to `OptionT[F, A]`

Sometimes you may have an `Option[A]` and/or `F[A]` and want to *lift* them into an `OptionT[F, A]`. For this purpose `OptionT` exposes two useful methods, namely `fromOption` and `liftF`, respectively. E.g.:

```tut:silent
val greetingFO: Future[Option[String]] = Future.successful(Some("Hello"))
val firstnameF: Future[String] = Future.successful("Jane")
val lastnameO: Option[String] = Some("Doe")
val ot: OptionT[Future, String] = for {
g <- OptionT(greetingFO)
f <- OptionT.liftF(firstnameF)
l <- OptionT.fromOption(lastnameO)
} yield s"$g $f $l"
val result: Future[Option[String]] = ot.value // Future(Some("Hello Jane Doe"))
```

## Beyond map

Sometimes the operation you want to perform on an `Option[Future[String]]` might not be as simple as just wrapping the `Option` method in a `Future.map` call. For example, what if we want to greet the customer with their custom greeting if it exists but otherwise fall back to a default `Future[String]` greeting? Without `OptionT`, this implementation might look like:
Expand Down
6 changes: 6 additions & 0 deletions tests/src/test/scala/cats/tests/OptionTTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ class OptionTTests extends CatsSuite {
}
}

test("liftF") {
forAll { (xs: List[Int]) =>
xs.map(Option(_)) should ===(OptionT.liftF(xs).value)
}
}

test("show"){
val xor: String Xor Option[Int] = Xor.right(Some(1))
OptionT[Xor[String, ?], Int](xor).show should === ("Xor.Right(Some(1))")
Expand Down

0 comments on commit 246512e

Please sign in to comment.