-
Notifications
You must be signed in to change notification settings - Fork 0
/
EitherT.scala
119 lines (92 loc) · 3.49 KB
/
EitherT.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
package just.fp
import syntax.{leftOps, rightOps}
import just.fp.compat.EitherCompat
/**
* @author Kevin Lee
* @since 2019-03-24
*/
final case class EitherT[F[_], A, B](run: F[Either[A, B]]) {
def map[C](f: B => C)(implicit F: Functor[F]): EitherT[F, A, C] =
EitherT(F.map(run)(EitherCompat.map(_)(f)))
def ap[C](fa: EitherT[F, A, B => C])(implicit F: Applicative[F]): EitherT[F, A, C] =
EitherT(
F.ap(run)(F.map(fa.run) {
case fb @ Right(_) => {
case Right(b) =>
EitherCompat.map(fb)(fb => fb(b))
case l @ Left(_) =>
l.castR[C]
}
case l @ Left(_) => _ =>
l.castR[C]
})
)
def flatMap[C](f: B => EitherT[F, A, C])(implicit M: Monad[F]): EitherT[F, A, C] =
EitherT(
M.flatMap(run) {
case Right(b) =>
f(b).run
case Left(a) =>
M.pure(Left(a).castR[C])
}
)
def leftMap[C](f: A => C)(implicit F: Functor[F]): EitherT[F, C, B] =
EitherT(F.map(run)(_.left.map(f)))
def leftFlatMap[C](f: A => EitherT[F, C, B])(implicit M: Monad[F]): EitherT[F, C, B] =
EitherT(
M.flatMap(run) {
case Left(a) =>
f(a).run
case Right(b) =>
M.pure(Right(b).castL[C])
}
)
def isLeft(implicit F: Functor[F]): F[Boolean] =
F.map(run)(_.isLeft)
def isRight(implicit F: Functor[F]): F[Boolean] =
F.map(run)(_.isRight)
}
object EitherT extends EitherTMonadInstance {
def pure[F[_]: Applicative, A, B](b: B): EitherT[F, A, B] =
EitherT(Applicative[F].pure(Right(b)))
def pureLeft[F[_]: Applicative, A, B](a: A): EitherT[F, A, B] =
EitherT(Applicative[F].pure(Left(a)))
}
private trait EitherTFunctor[F[_], A] extends Functor[EitherT[F, A, *]] {
implicit def F: Functor[F]
override def map[B, C](fa: EitherT[F, A, B])(f: B => C): EitherT[F, A, C] =
fa.map(f)(F)
}
private trait EitherTApplicative[F[_], A] extends Applicative[EitherT[F, A, *]] with EitherTFunctor[F, A] {
implicit def F: Applicative[F]
override def pure[B](b: => B): EitherT[F, A, B] = EitherT(F.pure(Right(b)))
def pureLef[B](a: => A): EitherT[F, A, B] = EitherT(F.pure(Left(a)))
override def ap[B, C](fa: => EitherT[F, A, B])(fab: => EitherT[F, A, B => C]): EitherT[F, A, C] =
fa.ap(fab)(F)
}
private trait EitherTMonad[F[_], A] extends Monad[EitherT[F, A, *]] with EitherTApplicative[F, A] {
implicit def F: Monad[F]
}
sealed abstract class EitherTFunctorInstance {
implicit def eitherTFunctor[F[_], A](implicit F0: Functor[F]): Functor[EitherT[F, A, *]] = new EitherTFunctor[F, A] {
override implicit val F: Functor[F] = F0
}
}
sealed abstract class EitherTApplicativeInstance extends EitherTFunctorInstance {
implicit def eitherTApplicative[F[_], A](implicit F0: Applicative[F]): Applicative[EitherT[F, A, *]] =
new EitherTApplicative[F, A] {
override implicit val F: Applicative[F] = F0
}
}
sealed abstract class EitherTMonadInstance extends EitherTApplicativeInstance {
implicit def eitherTMonad[F[_], A](implicit F0: Monad[F]): Monad[EitherT[F, A, *]] = new EitherTMonad[F, A] {
override implicit val F: Monad[F] = F0
override def flatMap[B, C](ma: EitherT[F, A, B])(f: B => EitherT[F, A, C]): EitherT[F, A, C] =
ma.flatMap(f)(F)
}
implicit def eitherTEqual[F[_], A, B](implicit EQ: Equal[F[Either[A, B]]]): Equal[EitherT[F, A, B]] =
new Equal[EitherT[F, A, B]] {
override def equal(x: EitherT[F, A, B], y: EitherT[F, A, B]): Boolean =
EQ.equal(x.run, y.run)
}
}