Попробуйте использовать псевдоним типа с DoesT, получите ошибку компиляции.
type FuEiErr[T] = Future[Either[Error, T]]
type FuEiErrInt = Future[Either[Error, Int]]
case class Error(msg: String)
def fA(x:Int): FuEiErr[Int] = Future(Right(x)) // compile error
def fB(x:Int): FuEiErr[Int] = Future(Right(x))
// def fA(x:Int): FuEiErrInt = Future(Right(x)) // ok
// def fB(x:Int): FuEiErrInt = Future(Right(x))
@main def TestEitherT(): Unit =
(for {
a <- EitherT(fA(7))
b <- EitherT(fB(42))
} yield { (b) }).value.map {
case Left(err) => println(s"Error: ${err.msg}")
case Right(res) => println(s"Result: ${res}")
}
Получена ошибка: «Для параметра F карты метода в классе DoesT не найден экземпляр типа Cats.Functor[F]». где: F — переменная типа с ограничением >: [X0] =>> scala.concurrent.Future[Either[Error, X0]] scala.concurrent.Future[X0] и <: [_] =>> Any
Спасибо за помощь!
@LuisMiguelMejíaSuárez просто любопытно, почему? :)
@DmytroMitin На самом деле много причин, типизированные ошибки, по моему мнению, в большинстве случаев являются плохой идеей. EitherT
не очень хорошо работает с параллелизмом. Cats не дает никаких гарантий относительно порядка выполнения Future
, особенно с traverse
и особенно в сочетании с EitherT
. Это всего лишь смесь для катастрофы. IME намного проще: просто придерживаться конкретного IO
и использовать канал отказа или специальные ADT.
Что ж, активно используйте DoesT в среде playframework (клиентская и серверная часть), пока никаких проблем. Future гораздо проще в использовании, чем IO, не нужна чистая функциональность, возможность отмены... Имея уже кучу библиотек для управления (+ миграция со Scala/Playframework 2 -> 3), не хотите платить цену для дополнительной зависимости и сложности с эффектом кошек (или ZIO).
@RobertJo, ну, если хочешь использовать Future
круто, делай, что хочешь. Но не путайте его с кошками, это доставит вам неприятности. Если вас вообще не волнует поведение выполнения ваших операций, в этот момент вообще не используйте Future
.
Для справки: последний выпуск кошек сломал traverse
для Future
(опять): github.com/typelevel/cats/issues/4617 - Именно такие вещи я имел в виду, когда говорил об использовании Futures
с кошками. это была плохая идея - C.C. @ДмитроМитин
@LuisMiguelMejíaSuárez Спасибо за ссылку. Да, Future на самом деле не монада stackoverflow.com/questions/27454798/is-future-in-scala-a-monad Возможно, экземпляры должны быть в Alleycats.
@DmytroMitin да, я уже пытался это сделать, но это сложная и несколько деликатная тема: github.com/typelevel/cats/pull/4182 ; нам, по крайней мере, удалось мягко объявить их устаревшими в документации: github.com/typelevel/cats/issues/4190 - TL;DR; Я участвую в крестовом походе, рассказывая всем людям, которых вижу, которые используют кошек с Future
, чтобы прекратить :p
Просто параметры типа не выводились. Пытаться
for {
a <- EitherT[Future, Error, Int](fA(7))
b <- EitherT[Future, Error, Int](fB(42))
}
Да, если вы проверите эту историю: scastie.scala-lang.org/BalmungSan/W8Ai5HhZTXGbStcXgqSlSw/18 вы увидите, что предполагаемый тип для a
— это что-то очень странное, например EitherT[[X] =>> Future[Either[Error, X] | X], Error, Int]
, что и приводит к сбою при вызове Functor
. - Похоже, это ошибка/регрессия в компиляторе, поскольку это работает в Scala 2: scastie.scala-lang.org/BalmungSan/W8Ai5HhZTXGbStcXgqSlSw/24 мой совет @RobertoJo - открыть заявку по этому поводу
Для справки:
EitherT
обычно является плохой идеей, и использовать кошек сFuture
тоже плохая идея.