You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/faq.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -68,7 +68,7 @@ It's really common to have a `List` of values with types like `Option`, `Either`
68
68
69
69
## Where is ListT?
70
70
71
-
There are monad transformers for various types, such as [OptionT](datatypes/optiont.md), so people often wonder why there isn't a `ListT`. For example, in the following example, people might reach for `ListT` to simplify making nested `map` and `exists` calls:
71
+
There are monad transformers for various types, such as [OptionT](monadtransformers/optiont.md), so people often wonder why there isn't a `ListT`. For example, in the following example, people might reach for `ListT` to simplify making nested `map` and `exists` calls:
An instance of [`OptionT[F, A]`](datatypes/optiont.md) can be thought of as a wrapper over `F[Option[A]]`
229
-
which adds a couple of useful methods specific to nested types that aren't available in `F` or `Option` itself.
230
-
Most typically, your `F` will be `Future` (or sometimes slick's `DBIO`, but this requires having an implementation of Cats type classes like `Functor` or `Monad` for `DBIO`).
231
-
Wrappers such as `OptionT` are generally known as _monad transformers_.
232
-
233
-
A quite common pattern is mapping the inner value stored inside an instance of `F[Option[A]]` to an instance of `F[Option[B]]` with a function of type `A => B`.
With the use of `OptionT`, this can be simplified as follows:
247
-
248
-
```scala mdoc:silent
249
-
defmappedResultFuture2:OptionT[Future, String] =OptionT(resultFuture).map { value =>
250
-
// Do something with the value and return String
251
-
???
252
-
}
253
-
```
254
-
255
-
The above `map` will return a value of type `OptionT[Future, String]`.
256
-
257
-
To get the underlying `Future[Option[String]]` value, simply call `.value` on the `OptionT` instance.
258
-
It's also a viable solution to fully switch to `OptionT[Future, A]` in method parameter/return types and completely (or almost completely) ditch `Future[Option[A]]` in type declarations.
259
-
260
-
There are several ways to construct an `OptionT` instance.
261
-
The method headers in the table below are slightly simplified: the type parameters and type classes required by each method are skipped.
262
-
263
-
| Method | Takes | Returns |
264
-
| :---: | :---: | :---: |
265
-
|`OptionT.apply` or `OptionT(...)`|`F[Option[A]]`|`OptionT[F, A]`|
In practice, you're most likely to use `map` and `semiflatMap`.
286
-
287
-
As is always the case with `flatMap` and `map`, you can use it not only explicitly, but also under the hood in `for` comprehensions, as in the example below:
The `OptionT[Future, Money]` instance returned by `getReservedFundsForUser` will enclose a `None` value if any of the three composed methods returns an `OptionT` corresponding to `None`.
306
-
Otherwise, if the result of all three calls contains `Some`, the final outcome will also contain `Some`.
307
-
308
-
309
-
## EitherT
310
-
311
-
```scala mdoc:silent
312
-
importcats.data.EitherT
313
-
```
314
-
315
-
[`EitherT[F, A, B]`](datatypes/eithert.md) is the monad transformer for `Either` — you can think of it as a wrapper over a `F[Either[A, B]]` value.
316
-
317
-
Just as in the above section, I simplified the method headers, skipping type parameters or their context bounds and lower bounds.
318
-
319
-
Let's have a quick look at how to create an `EitherT` instance:
320
-
321
-
| Method | Takes | Returns |
322
-
| :---: | :---: | :---: |
323
-
|`EitherT.apply` or `EitherT(...)`|`F[Either[A, B]]`|`EitherT[F, A, B]`|
324
-
|`EitherT.fromEither`|`Either[A, B]`|`EitherT[F, A, B]` (wraps the provided `Either` value into `F`) |
325
-
|`EitherT.right` or `EitherT.liftF`|`F[B]`|`EitherT[F, A, B]` (wraps value inside `F[B]` into `Right`) |
326
-
|`EitherT.left`|`F[A]`|`EitherT[F, A, B]` (wraps value inside `F[B]` into `Left`) |
327
-
|`EitherT.pure`|`A`|`EitherT[F, A, B]` (wraps value into `Right` and then into `F`) |
328
-
329
-
Another useful way to construct an `EitherT` instance is to use `OptionT`'s methods `toLeft` and `toRight`:
.toRight(left =UserNotFoundException(s"user not found, userId=$userId"))
341
-
}
342
-
```
343
-
344
-
`toRight` is pretty analogous to the method `Either.fromOption` mentioned before: just as `fromOption` built an `Either` from an `Option`, `toRight` creates an `EitherT` from an `OptionT`.
345
-
If the original `OptionT` stores `Some` value, it will be wrapped into `Right`; otherwise the value provided as the `left` parameter will be wrapped into a `Left`.
346
-
To provide the `left` value within the monad, there is corresponding `toRightF` method.
347
-
348
-
`toLeft` is `toRight`'s counterpart which wraps the `Some` value into `Left` and transforms `None` into `Right` enclosing the provided `right` value.
349
-
This is less commonly used in practice, but can serve e.g. for enforcing uniqueness checks in code.
350
-
We return `Left` if the value has been found, and `Right` if it doesn't yet exist in the system.
351
-
352
-
The methods available in `EitherT` are pretty similar to those we've seen in `OptionT`, but there are some notable differences.
353
-
354
-
You might get into some confusion at first when it comes to e.g. `map`.
355
-
In the case of `OptionT`, it was pretty obvious what should be done: `map` should go over the `Option` enclosed within `Future`, and then map the enclosed `Option` itself.
356
-
This is slightly less obvious in case of `EitherT`: should it map over both `Left` and `Right` values, or only the `Right` value?
357
-
358
-
The answer is that `EitherT` is _right-biased_, therefore plain `map` actually deals with the `Right` value.
359
-
This is unlike `Either` in the Scala standard library up to 2.11, which is in turn _unbiased_: there's no `map` available in `Either`, only for its left and right projections.
360
-
361
-
Having said that, let's take a quick look at the right-biased methods that `EitherT` offers:
362
-
363
-
| Method | Takes | Returns |
364
-
| :---: | --- | --- |
365
-
|`map[D]`|`B => D`|`EitherT[F, A, D]`|
366
-
|`subflatMap[D]`|`B => Either[A, D]`|`EitherT[F, A, D]`|
367
-
|`semiflatMap[D]`|`B => F[D]`|`EitherT[F, A, D]`|
368
-
|`flatMapF[D]`|`B => F[Either[A, D]]`|`EitherT[F, A, D]`|
369
-
|`flatMap[D]`|`B => EitherT[F, A, D]`|`EitherT[F, A, D]`|
370
-
371
-
As a side note, there are also certain methods in `EitherT` (that you're likely to need at some point) which map over the `Left` value, like `leftMap`, or over both `Left` and `Right` values, like `fold` or `bimap`.
372
-
373
-
`EitherT` is very useful for fail-fast chained verifications:
In the above example, we're running various checks against the item one by one.
410
-
If any of the checks fails, the resulting `EitherT` will contain a `Left` value.
411
-
Otherwise, if all of the checks yield a `Right` (of course we mean a `Right` wrapped into an `EitherT`), then the final outcome will also contain `Right`.
412
-
This is a fail-fast behavior: we're effectively stopping the `for` comprehension flow at the first `Left`-ish result.
413
-
414
-
If you're instead looking for validation that accumulates the errors (e.g. when dealing with user-provided form data), `cats.data.Validated` may be a good choice.
415
-
416
-
417
-
418
219
# Common issues
419
220
420
221
The Cats type class instances for standard library types are available in implicit scope and hence no longer have to be imported. If anything doesn't compile as expected, first make sure all the required Cats syntax implicits are in the scope — try importing ```cats.syntax.all._``` and see if the problem persists. The only exception is here is Cat's own ```Order``` and ```PartialOrder``` type classes which are available by importing ```cats.implicits._```.
0 commit comments