Рассмотрим предложение параметра типа MonadError
trait MonadError[F[_], E]
Обратите внимание, что F
и E
имеют разные формы (или типы):
F - a type constructor of * -> * kind
E - a proper type of * kind
разница между конструктором типа и правильным типом аналогична разнице между List
и List[Int]
, то есть конструктору типа List
требуется аргумент типа * от Int
до конструкция правильный тип 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.
Мы видим, что это конструктор типа формы * -> *
, который соответствует форме конструктора типа F
. . Поэтому мы можем написать
scala> MonadError[IO, Throwable]
res2: cats.MonadError[cats.effect.IO,Throwable] = cats.effect.IOLowPriorityInstances$IOEffect@75c81e89
Здесь - еще несколько примеров
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- проектор и является альтернативой использованию псевдонима типа для преобразования, например, * -> * -> *
вида в требуемый * -> *
вид
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.