Допустим, я определил класс типов для вычислений кэширования.
trait Cached[F[_], A] {
def value: F[A]
}
Интуитивно, Cached
оборачивает вычисление, чтобы мы могли либо оценить его во время выполнения, либо вместо этого загрузить результат из базы данных.
Я хотел бы определить экземпляры Functor, Applicative и Monad для этой черты.Использование Kind-проектора для облегчения моей жизни:
import scalaz._, Scalaz._
object Cached {
def apply[F[_], A](f: => F[A]): Cached[F, A] = new Cached[F, A] {
override def value: F[A] = f
}
implicit def functor[F[_] : Functor]: Functor[Cached[F, ?]] = new Functor[Cached[F, ?]] {
override def map[A, B](fa: Cached[F, A])(f: A => B): Cached[F, B] =
Cached(fa.value map f)
}
implicit def applicative[F[_] : Applicative]: Applicative[Cached[F, ?]] = new Applicative[Cached[F, ?]] {
override def point[A](a: => A): Cached[F, A] = Cached(a.point[F])
override def ap[A, B](fa: => Cached[F, A])(f: => Cached[F, A => B]): Cached[F, B] =
Cached(fa.value <*> f.value)
}
implicit def monad[F[_] : Monad](implicit app: Applicative[Cached[F, ?]], func: Functor[Cached[F, ?]]): Monad[Cached[F, ?]] =
new Monad[Cached[F, ?]] {
override def point[A](a: => A): Cached[F, A] = app.point(a)
override def bind[A, B](fa: Cached[F, A])(f: A => Cached[F, B]): Cached[F, B] =
Cached(func.map(fa)(f).value >>= (_.value))
}
}
Пока все хорошо.Теперь давайте используем монаду в простом примере:
import Cached._
val y = Cached(2.point[Id])
val z = for {
a <- Cached(1.point[Id])
b <- y
} yield a + b
При выполнении кода во время выполнения я получаю следующую ошибку:
[error] diverging implicit expansion for type scalaz.Applicative[[β$4$]Cached[scalaz.Scalaz.Id,β$4$]]
[error] starting with method monad in object Cached
[error] a <- Cached(1.point[Id])
[error] ^
[error] diverging implicit expansion for type scalaz.Applicative[[β$4$]Cached[scalaz.Scalaz.Id,β$4$]]
[error] starting with method monad in object Cached
[error] b <- y
[error] ^
[error] two errors found
[error] (Test / compileIncremental) Compilation failed
Я знаю, что неявное расширение происходит, когдакомпилятор застрял в цикле при расширении неявных определений, но я не понимаю, почему это происходит с моим кодом.
Я был бы признателен, если бы кто-то мог указать мне правильное направление.Я довольно плохо знаком с концепциями функционального программирования, поэтому то, что я здесь сделал, может даже не иметь смысла!