【问题标题】:How to use the MonadError with the effect type IO?如何将 MonadError 与效果类型 IO 一起使用?
【发布时间】:2020-06-21 13:00:25
【问题描述】:

我正在尝试为我的无标记代数编写测试,它使用MonadError

这是带有解释器的无标记代数:

trait DbConnector[F[_]] {
  def read(url: DbUrl, user: DbUser, pw: DbPw): F[DbParams]
}


object DbConnector {

  def apply[F[_]](implicit dc: DbConnector[F]): dc.type = dc

  def impl[F[_] : MonadError[*[_], Throwable]](env: Environment[F])
  : DbConnector[F] =
    new LiveDbConnector[F](env)

}

以及带有MonadError 实例Either 的测试类:

class DbConnectorSpec extends munit.FunSuite {
  test("Environment variables are not set") {

    val monadError = MonadError[IO[Either[DbError, DbParams]], DbError]
    implicit val badEnv = DbConnector.impl(LiveBadEnvironment())


  }
}

代码没有被编译,因为错误信息:

cats.effect.IO[Either[io.databaker.db.DbError,io.databaker.db.DbParams]] takes no type parameters, expected: 1
[error]     val monadErr = MonadError[IO[Either[DbError, DbParams]], DbError]

MonadError 对我来说是新的,这是我第一次尝试使用它。我在https://www.scalawithcats.com/dist/scala-with-cats.html 上阅读了MonadError 的概念。

如何让它运行?

【问题讨论】:

    标签: scala scala-cats


    【解决方案1】:

    考虑MonadError的类型参数子句

    trait MonadError[F[_], E]
    

    注意FE 的不同形状(或种类):

    F - a type constructor of * -> * kind
    E - a proper type of * kind
    

    类型构造函数和正确类型之间的difference就像ListList[Int]之间的区别,即类型构造函数List需要一个类型参数Intconstruct 正确的类型List[Int]

    现在考虑IO[Either[Throwable,Int]]的类型

    scala> :kind -v IO[Either[Throwable, Int]]
    cats.effect.IO[Either[Throwable,Int]]'s kind is A
    *
    This is a proper type.
    

    我们看到它具有正确类型的形状,因此它不能代替F

    scala> MonadError[IO[Either[Throwable, Int]], Throwable]
    <console>:25: error: cats.effect.IO[Either[Throwable,Int]] takes no type parameters, expected: one
           MonadError[IO[Either[Throwable, Int]], Throwable]
    

    现在考虑IO的类型

    scala> :kind -v IO
    cats.effect.IO's kind is F[+A]
    * -(+)-> *
    This is a type constructor: a 1st-order-kinded type.
    

    我们看到它是* -&gt; * 形状的类型构造函数,它与F 类型构造函数的形状相匹配。所以我们可以写

    scala> MonadError[IO, Throwable]
    res2: cats.MonadError[cats.effect.IO,Throwable] = cats.effect.IOLowPriorityInstances$IOEffect@75c81e89
    

    Here 是一些进一步的例子

    import cats._
    import cats.data._
    import cats.effect.IO
    import cats.instances.either._
    import cats.instances.try_._
    import cats.instances.future._
    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext.Implicits.global
    import scala.util.Try
    
    MonadError[Future, Throwable]
    MonadError[Try, Throwable]
    MonadError[IO, Throwable]
    MonadError[Either[String, *], String]
    MonadError[EitherT[IO, String, *], String]
    MonadError[EitherT[Future, String, *], String]
    

    注意Either[String, *] 中的* 语法来自kind-projector,它是使用类型别名将* -&gt; * -&gt; * 类型转换为必需的* -&gt; * 类型的替代方法

    scala> :kind -v Either[String, *]
    scala.util.Either[String,?]'s kind is F[+A]
    * -(+)-> *
    This is a type constructor: a 1st-order-kinded type.
    
    scala> type MyError[+A] = Either[String, A]
    defined type alias MyError
    
    scala> :kind -v MyError
    MyError's kind is F[+A]
    * -(+)-> *
    This is a type constructor: a 1st-order-kinded type.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-03
      • 1970-01-01
      相关资源
      最近更新 更多