【问题标题】:Scalaz error combining EitherT and OptionTScalaz 错误结合了 EitherT 和 OptionT
【发布时间】:2017-10-22 17:59:50
【问题描述】:

我正在使用带有 OptionT 的 scalaZ 的 monad 转换器 EitherT 做一个示例,但我有一个我不明白的编译错误。

这是我的示例代码

class EitherTMonadTransformer {

  case class Error(msg: String)

  case class User(username: String, email: String)

  def authenticate(token: String): Future[Error \/ String] = Future {
    \/.right("token")
  }

  def getUser(username: String): Future[Option[User]] = Future {
    Some(User("paul", "osmosis_paul@gmail.com"))
  }

  val userObj: Future[\/[Error, Nothing]] =
    (for {
      username <- EitherT(authenticate("secret1234"))
      user <- OptionT(getUser(username))
    } yield user.username).run


  @Test
  def eitherTAndOptionT(): Unit = {
    println(userObj)
  }
}

编译错误说

Error:(32, 12) type mismatch;
 found   : scalaz.OptionT[scala.concurrent.Future,String]
 required: scalaz.EitherT[scala.concurrent.Future,EitherTMonadTransformer.this.Error,?]
      user <- OptionT(getUser(username))

知道有什么问题吗?

问候。

【问题讨论】:

    标签: scala scalaz


    【解决方案1】:

    问题在于,在 for 表达式中,您不能随意混合和匹配不同的 monad。在这种特殊情况下,您尝试将 OptionT monad 与 EitherT 混合。请记住,monad 转换器本身就是 monad。编译器一看到username &lt;- EitherT(authenticate("secret1234")) 这一行,就会推断EitherT 是for 表达式中使用的monad,并期望它用于其余部分。一种可能的解决方案是更改 getUser 方法返回的类型,例如:

    def getUser(username: String): Future[Error \/ User] = Future {
      \/.right(User("paul", "osmosis_paul@gmail.com"))
    }
    

    当然,你也必须按如下方式更改 for 表达式:

    val userObj: Future[\/[Error, String]] =
      (for {
        username <- EitherT(authenticate("secret1234"))
        user <- EitherT(getUser(username))
      } yield user.username).run
    

    这样类型对齐并且编译器会很高兴地接受它们。

    【讨论】:

    • 我明白了,因为所有管道都只接受一种签名类型,谢谢您的解释。
    猜你喜欢
    • 1970-01-01
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多