Не могу сделать простой пример без тега
Я читал о финале без тегов и думаю, что это здорово. Я хотел построить свой собственный маленький пример этого шаблона и получил проблему.
Это мой код:
trait Calculator[F[_]] {
def sum(a: Int, b: Int): F[Either[Throwable, Int]]
def minus(a: Int, b: Int): F[Either[Throwable, Int]]
}
object calculatorInstances {
implicit val futureCalculator: Calculator[Future] = new Calculator[Future] {
override def sum(a: Int, b: Int) =
Future {
Try(a + b).toEither
}
override def minus(a: Int, b: Int) =
Future {
Try(a - b).toEither
}
}
}
import calculatorInstances.futureCalculator
def getPlusAndMinus[F[_]: Monad: Calculator](a: Int, b: Int): F[Either[String, Int]] = {
for {
sum <- Calculator[F].sum(a, b)
res <- Calculator[F].minus(sum, b)
} yield res
}
Этот код не работает из-за not found: value Calculator
ошибка. Как я могу сделать это правильно?
1 ответ
Добавить материал:
object Calculator {
def apply[F[_]: Calculator]: Calculator[F] = implicitly
}
Лучше ставить экземпляры типа class Calculator[F[_]]
(как неявный futureCalculator
) к тому же объекту-компаньону Calculator
иначе вам придется import calculatorInstances._
,
Не забудь import cats.syntax.flatMap._
а также import cats.syntax.functor._
,
sum
в sum <- Calculator[F].sum(a, b)
имеет тип Either[Throwable,Int]
но sum
в Calculator[F].minus(sum, b)
как ожидается, будет Int
,
Возможно возвращающий тип getPlusAndMinus
должно быть F[Either[Throwable, Int]]
вместо F[Either[String, Int]]
,
Возможно, самый простой способ исправить for
Понимание заключается в использовании монадного трансформатора:
def getPlusAndMinus[F[_] : Monad: Calculator](a: Int, b: Int): F[Either[Throwable, Int]] = {
(for {
sum <- EitherT(Calculator[F].sum(a, b))
res <- EitherT(Calculator[F].minus(sum, b))
} yield res).value
}
На всякий случай весь код:
import cats.data.EitherT
import cats.Monad
//import cats.syntax.flatMap._ // not necessary if we use EitherT
//import cats.syntax.functor._
import scala.concurrent.Future
import scala.language.higherKinds
import scala.util.Try
import scala.concurrent.ExecutionContext.Implicits.global
object App {
trait Calculator[F[_]] {
def sum(a: Int, b: Int): F[Either[Throwable, Int]]
def minus(a: Int, b: Int): F[Either[Throwable, Int]]
}
object Calculator {
def apply[F[_]: Calculator]: Calculator[F] = implicitly
implicit val futureCalculator: Calculator[Future] = new Calculator[Future] {
override def sum(a: Int, b: Int) =
Future {
Try(a + b).toEither
}
override def minus(a: Int, b: Int) =
Future {
Try(a - b).toEither
}
}
}
def getPlusAndMinus[F[_] : Monad: Calculator](a: Int, b: Int): F[Either[Throwable, Int]] = {
(for {
sum <- EitherT(Calculator[F].sum(a, b))
res <- EitherT(Calculator[F].minus(sum, b))
} yield res).value
}
}