【问题标题】:EitherT with multiple return types具有多种返回类型的 EitherT
【发布时间】:2020-01-06 22:53:03
【问题描述】:

我正在尝试使用 for-comprehension 和 EitherT 组合期货,但由于返回类型,我遇到了麻烦。请有人可以解释为什么这不能编译,我怎样才能让它编译改变理解?

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
  }
}

【问题讨论】:

    标签: scala scala-cats for-comprehension


    【解决方案1】:

    为了便于理解,链中第一步的类型和偏差决定了链中所有其他步骤的类型。因为Either 是右偏的,所以我们只能按照@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 可以变化。让您的理解变得愉快的一种方法是像这样从Ls 创建代数数据类型

      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)))
    

    【讨论】:

      猜你喜欢
      • 2016-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-07
      • 1970-01-01
      • 2016-09-09
      相关资源
      最近更新 更多