![](/img/trans.png)
[英]Why implicit class in Scala must reside in another trait/class/object?
[英]Scala: deferring a trait method to an implicit class in parent trait's object
具体来说,我正在尝试通过Applicative
扩展我的Functor
类型类。
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)))
}
}
要点是我必须为所有Applicative
s实现fmap
,但实际上它应该与FunctorOps
类中定义的方法相同。 如何以最干净的方式做到这一点?
您正确使用了Applicative[F] <: Functor[F]
部分,但您应该真正考虑一下这是什么意思。 这意味着Applicative[F]
的实例也提供了Functor[F]
的方法。 也就是说,您不能同时拥有两个implicit val listFunctor: Functor[List]; implicit val listApplicative: Applicative[List]
implicit val listFunctor: Functor[List]; implicit val listApplicative: Applicative[List]
,因为当您要求implicit param: Functor[List]
时,编译器会感到困惑。 您应该只有后者。 然后,您尝试做的事情是荒谬的,因为您是根据F
本身定义F
的Functor
实例的(因为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]
的状态fmap
(或根据需要覆盖fmap
)。 现在您遇到了另一个问题,因为Functor[Seq]
实例实际上在object Applicative
,所以隐式搜索需要解决一些问题,但是解决隐式分辨率要比强制执行单独的Functor
和Applicative
实例的一致性少。 在这种情况下,如果Seq
是您无法控制其伴随对象的类型,则cats
至少会执行以下操作
package instances {
trait SeqInstances {
implicit val seqFunctor: Functor[Seq] = ???
}
package object seq extends SeqInstances
package object all extends SeqInstances
with AAAInstances
with BBBInstances
with ...
}
仅供参考:我建议使用您的类型类方法
def fmap[A, B](r: F[A])(f: A => B): F[B]
def fapply[A, B](r: F[A])(f: F[A => B]): F[B]
在ApplicativeOps
进行flip fapply
可能会很好
def ylppaf[I, B](f: F[I])(implicit ev: A =:= (I => B))
: F[B] = F.fapply(a.fmap(ev))(f)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.