具有多种 return 类型的 EitherT
EitherT with multiple return types
我正在尝试用 for-comprehension 和 EitherT 编写 futures,但由于 return 类型,我遇到了麻烦。请有人解释为什么这不能编译,我怎样才能通过改变 for-comprehension 来编译它?
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import cats.data.EitherT
import cats.implicits._
object CatsApp extends App {
case class L1(a: String)
case class L2(a: String)
case class L3(a: String)
case class R1(num: Int)
case class R2(num: Int)
case class R3(num: Int)
def func1: Future[Either[L1, R1]] = {
if (true) Future(Right(R1(1)))
else Future(Left(L1("A")))
}
def func2: Future[Either[L2, R2]] = {
if (true) Future(Right(R2(1)))
else Future(Left(L2("A")))
}
def func3(a: R1, b: R2): Future[Either[L3, R3]] = {
if (true) Future(Right(R3(a.num + b.num)))
else Future(Left(L3("A")))
}
def comp = {
for {
f1 <- EitherT(func1)
f2 <- EitherT(func2)
f3 <- EitherT(func3(f1, f2))
} yield f3
}
}
在for-comprehension中,链中第一个步骤的类型和偏差决定了链中所有其余步骤的类型。因为 Either
是右偏的,我们只能在 for-comprehension 的步骤之间更改正确的类型,正如@Krzysztof 所建议的那样。例如,
val e1: Either[String, Int] = Right(42)
val e2: Either[String, Char] = Right('A')
for {
num <- e1
char <- e2
} yield "I compile despite having different Rights"
在您的情况下,第一步 EitherT(func1)
的类型是 EitherT[Future, L1, R1]
,因此接下来的步骤 EitherT(func2)
和 EitherT(func3(f1, f2))
必须具有以下形状的类型
EitherT[Future, L1, X]
其中只有 X
可以变化。让你的理解快乐的一种方法是从 L
中创建 代数数据类型 ,就像这样
sealed abstract class L(val a: String)
final case class L1(s: String) extends L(s)
final case class L2(s: String) extends L(s)
final case class L3(s: String) extends L(s)
这是一个有效的 example
object CatsApp extends App {
sealed abstract class L(val a: String)
final case class L1(s: String) extends L(s)
final case class L2(s: String) extends L(s)
final case class L3(s: String) extends L(s)
case class R1(num: Int)
case class R2(num: Int)
case class R3(num: Int)
def func1: Future[Either[L, R1]] = {
if (true) Future(Right(R1(1)))
else Future(Left(L1("A")))
}
def func2: Future[Either[L, R2]] = {
if (true) Future(Right(R2(1)))
else Future(Left(L2("A")))
}
def func3(a: R1, b: R2): Future[Either[L, R3]] = {
if (true) Future(Right(R3(a.num + b.num)))
else Future(Left(L3("A")))
}
def comp: EitherT[Future, L, R3] = {
for {
f1 <- EitherT(func1)
f2 <- EitherT(func2)
f3 <- EitherT(func3(f1, f2))
} yield f3
}
comp.value.andThen(v => println(v))
}
输出
Success(Right(R3(2)))
我正在尝试用 for-comprehension 和 EitherT 编写 futures,但由于 return 类型,我遇到了麻烦。请有人解释为什么这不能编译,我怎样才能通过改变 for-comprehension 来编译它?
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import cats.data.EitherT
import cats.implicits._
object CatsApp extends App {
case class L1(a: String)
case class L2(a: String)
case class L3(a: String)
case class R1(num: Int)
case class R2(num: Int)
case class R3(num: Int)
def func1: Future[Either[L1, R1]] = {
if (true) Future(Right(R1(1)))
else Future(Left(L1("A")))
}
def func2: Future[Either[L2, R2]] = {
if (true) Future(Right(R2(1)))
else Future(Left(L2("A")))
}
def func3(a: R1, b: R2): Future[Either[L3, R3]] = {
if (true) Future(Right(R3(a.num + b.num)))
else Future(Left(L3("A")))
}
def comp = {
for {
f1 <- EitherT(func1)
f2 <- EitherT(func2)
f3 <- EitherT(func3(f1, f2))
} yield f3
}
}
在for-comprehension中,链中第一个步骤的类型和偏差决定了链中所有其余步骤的类型。因为 Either
是右偏的,我们只能在 for-comprehension 的步骤之间更改正确的类型,正如@Krzysztof 所建议的那样。例如,
val e1: Either[String, Int] = Right(42)
val e2: Either[String, Char] = Right('A')
for {
num <- e1
char <- e2
} yield "I compile despite having different Rights"
在您的情况下,第一步 EitherT(func1)
的类型是 EitherT[Future, L1, R1]
,因此接下来的步骤 EitherT(func2)
和 EitherT(func3(f1, f2))
必须具有以下形状的类型
EitherT[Future, L1, X]
其中只有 X
可以变化。让你的理解快乐的一种方法是从 L
中创建 代数数据类型 ,就像这样
sealed abstract class L(val a: String)
final case class L1(s: String) extends L(s)
final case class L2(s: String) extends L(s)
final case class L3(s: String) extends L(s)
这是一个有效的 example
object CatsApp extends App {
sealed abstract class L(val a: String)
final case class L1(s: String) extends L(s)
final case class L2(s: String) extends L(s)
final case class L3(s: String) extends L(s)
case class R1(num: Int)
case class R2(num: Int)
case class R3(num: Int)
def func1: Future[Either[L, R1]] = {
if (true) Future(Right(R1(1)))
else Future(Left(L1("A")))
}
def func2: Future[Either[L, R2]] = {
if (true) Future(Right(R2(1)))
else Future(Left(L2("A")))
}
def func3(a: R1, b: R2): Future[Either[L, R3]] = {
if (true) Future(Right(R3(a.num + b.num)))
else Future(Left(L3("A")))
}
def comp: EitherT[Future, L, R3] = {
for {
f1 <- EitherT(func1)
f2 <- EitherT(func2)
f3 <- EitherT(func3(f1, f2))
} yield f3
}
comp.value.andThen(v => println(v))
}
输出
Success(Right(R3(2)))