-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
flatMap.scala
137 lines (116 loc) · 4.36 KB
/
flatMap.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package cats
package syntax
trait FlatMapSyntax extends FlatMap.ToFlatMapOps {
implicit final def catsSyntaxFlatten[F[_]: FlatMap, A](ffa: F[F[A]]): FlattenOps[F, A] =
new FlattenOps[F, A](ffa)
implicit final def catsSyntaxIfM[F[_]: FlatMap](fa: F[Boolean]): IfMOps[F] =
new IfMOps[F](fa)
implicit final def catsSyntaxFlatMapIdOps[A](a: A): FlatMapIdOps[A] =
new FlatMapIdOps[A](a)
implicit final def catsSyntaxFlatMapOps[F[_]: FlatMap, A](fa: F[A]): FlatMapOps[F, A] =
new FlatMapOps[F, A](fa)
}
final class FlatMapOps[F[_], A](private val fa: F[A]) extends AnyVal {
/**
* Alias for [[flatMap]].
*/
def >>=[B](f: A => F[B])(implicit F: FlatMap[F]): F[B] = F.flatMap(fa)(f)
/**
* Alias for `fa.flatMap(_ => fb)`.
*
* Unlike `*>`, `fb` is defined as a by-name parameter, allowing this
* method to be used in cases where computing `fb` is not stack safe
* unless suspended in a `flatMap`.
*/
def >>[B](fb: => F[B])(implicit F: FlatMap[F]): F[B] = F.flatMap(fa)(_ => fb)
@deprecated("Use <* instead", "1.0.0-RC1")
private[syntax] def <<[B](fb: F[B])(implicit F: FlatMap[F]): F[A] = F.productL(fa)(fb)
@deprecated("Use productREval instead.", "1.0.0-RC2")
private[syntax] def followedByEval[B](fb: Eval[F[B]])(implicit F: FlatMap[F]): F[B] =
F.productREval(fa)(fb)
@deprecated("Use productLEval instead.", "1.0.0-RC2")
private[syntax] def forEffectEval[B](fb: Eval[F[B]])(implicit F: FlatMap[F]): F[A] =
F.productLEval(fa)(fb)
/**
* Like an infinite loop of >> calls. This is most useful effect loops
* that you want to run forever in for instance a server.
*
* This will be an infinite loop, or it will return an F[Nothing].
*
* Be careful using this.
* For instance, a List of length k will produce a list of length k^n at iteration
* n. This means if k = 0, we return an empty list, if k = 1, we loop forever
* allocating single element lists, but if we have a k > 1, we will allocate
* exponentially increasing memory and very quickly OOM.
*/
def foreverM[B](implicit F: FlatMap[F]): F[B] = F.foreverM[A, B](fa)
}
final class FlattenOps[F[_], A](private val ffa: F[F[A]]) extends AnyVal {
/**
* Flatten nested `F` values.
*
* Example:
* {{{
* scala> import cats.implicits._
* scala> type ErrorOr[A] = Either[String, A]
* scala> val x: ErrorOr[ErrorOr[Int]] = 3.asRight.asRight
* scala> x.flatten
* res0: ErrorOr[Int] = Right(3)
* }}}
*/
def flatten(implicit F: FlatMap[F]): F[A] = F.flatten(ffa)
}
final class IfMOps[F[_]](private val fa: F[Boolean]) extends AnyVal {
/**
* A conditional lifted into the `F` context.
*
* Example:
* {{{
* scala> import cats.{Eval, Now}
* scala> import cats.implicits._
*
* scala> val b1: Eval[Boolean] = Now(true)
* scala> val asInt1: Eval[Int] = b1.ifM(Now(1), Now(0))
* scala> asInt1.value
* res0: Int = 1
*
* scala> val b2: Eval[Boolean] = Now(false)
* scala> val asInt2: Eval[Int] = b2.ifM(Now(1), Now(0))
* scala> asInt2.value
* res1: Int = 0
* }}}
*/
def ifM[B](ifTrue: => F[B], ifFalse: => F[B])(implicit F: FlatMap[F]): F[B] = F.ifM(fa)(ifTrue, ifFalse)
}
final class FlatMapIdOps[A](private val a: A) extends AnyVal {
/**
* Example:
* {{{
* scala> import cats.implicits._
*
* scala> val a: Int = 10
* scala> a.tailRecM[Option,String](i => if (i == 20) Some(Right("done")) else Some(Left(i+1)))
* res0: Option[String] = Some(done)
*
* }}}
*/
def tailRecM[F[_], B](f: A => F[Either[A, B]])(implicit F: FlatMap[F]): F[B] = F.tailRecM(a)(f)
/**
* iterateForeverM is almost exclusively useful for effect types. For instance,
* A may be some state, we may take the current state, run some effect to get
* a new state and repeat.
*/
def iterateForeverM[F[_], B](f: A => F[A])(implicit F: FlatMap[F]): F[B] = F.iterateForeverM[A, B](a)(f)
}
trait FlatMapOptionSyntax {
implicit final def catsSyntaxFlatMapOptionOps[F[_]: FlatMap, A](foa: F[Option[A]]): FlatMapOptionOps[F, A] =
new FlatMapOptionOps[F, A](foa)
}
final class FlatMapOptionOps[F[_], A](private val fopta: F[Option[A]]) extends AnyVal {
/**
* This repeats an F until we get defined values. This can be useful
* for polling type operations on State (or RNG) Monads, or in effect
* monads.
*/
def untilDefinedM(implicit F: FlatMap[F]): F[A] = F.untilDefinedM[A](fopta)
}