具体来说,我尝试使用Functor
扩展我的Applicative
类型类。
trait Functor[F[_]] {
def fmap[A, B](r: F[A], f: A => B): F[B]
}
object Functor {
implicit class FunctorOps[A, F[_]: Functor](xs: F[A]) {
def fmap[B](f: A => B): F[B] = implicitly[Functor[F]].fmap(xs, f)
}
implicit def SeqFunctor: Functor[Seq] = new Functor[Seq] {
def fmap[A, B](r: Seq[A], f: A => B) = r map f
}
}
trait Applicative[F[_]] extends Functor[F] {
// What I want to do, but this *does not* work.
def fmap[A, B](r: F[A], f: A => B): F[B] = Functor.FunctorOps[A, F](r).fmap(f)
def pure[A](x: A): F[A]
def fapply[A, B](r: F[A], f: F[A => B]): F[B]
}
object Applicative {
implicit class ApplicativeOps[A, F[_]](a: F[A])(implicit F: Applicative[F]) {
def fapply[B](f: F[A => B]): F[B] = F.fapply(a, f)
}
implicit def SeqApplicative: Applicative[Seq] = new Applicative[Seq] {
def pure[A](x: A) = Seq(x)
def fapply[A, B](xs: Seq[A], fs: Seq[A => B]): Seq[B] = xs.flatMap(x => fs.map(_(x)))
}
}
它的要点是我必须为所有fmap
实现Applicative
,但它应该与我的FunctorOps
类中定义的方法相同。我该如何以最干净的方式做到这一点?
答案 0 :(得分:1)
你有Applicative[F] <: Functor[F]
部分,但你应该考虑这意味着什么。这意味着Applicative[F]
的实例也为Functor[F]
提供了方法。也就是说,你不能同时拥有implicit val listFunctor: Functor[List]; implicit val listApplicative: Applicative[List]
,因为当你要求implicit param: Functor[List]
时,编译器会感到困惑。你应该只有后者。您尝试做的事情是荒谬的,因为您根据自身定义了Functor
F
个实例(因为Applicative[F]
Functor[F]
),无论如何最终只有两个Functor[Seq]
。
fmap
然后移除pure
个实例并保持fapply
的实际状态(或覆盖trait Applicative[F[_]] extends Functor[F] {
override def fmap[A, B](r: F[A], f: A => B): F[B] = fapply(r, pure(f))
def pure[A](x: A): F[A]
def fapply[A, B](r: F[A], f: F[A => B]): F[B]
}
,如果您愿意)。你现在有一个不同的问题,因为隐式搜索有点转过来,因为Functor[Seq]
实例实际上在Applicative[Seq]
,但修复隐式解决方案比强制执行单独{{1}的一致性更麻烦}和fmap
个实例。在这种情况下,Functor[Seq]
是一种您无法控制其伴随对象的类型,至少cats
会执行类似
object Applicative
仅供参考:我建议讨论你的类型类方法
Functor
在Applicative
Seq
可能会很不错
package instances {
trait SeqInstances {
implicit val seqFunctor: Functor[Seq] = ???
}
package object seq extends SeqInstances
package object all extends SeqInstances
with AAAInstances
with BBBInstances
with ...
}