[英]Scala: deferring a trait method to an implicit class in parent trait's object
Specifically, I'm trying to extend my Functor
typeclass with Applicative
. 具体来说,我正在尝试通过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)))
}
}
The gist of it is I have to implement fmap
for all Applicative
s, but it should really be the same method as defined in my FunctorOps
class. 要点是我必须为所有Applicative
s实现fmap
,但实际上它应该与FunctorOps
类中定义的方法相同。 How do I do this in the cleanest way possible? 如何以最干净的方式做到这一点?
You got the Applicative[F] <: Functor[F]
part right, but you should really think about what that means. 您正确使用了Applicative[F] <: Functor[F]
部分,但您应该真正考虑一下这是什么意思。 It means that an instance of Applicative[F]
also provides the methods for Functor[F]
. 这意味着Applicative[F]
的实例也提供了Functor[F]
的方法。 That is, you can't have both implicit val listFunctor: Functor[List]; implicit val listApplicative: Applicative[List]
也就是说,您不能同时拥有两个implicit val listFunctor: Functor[List]; implicit val listApplicative: Applicative[List]
implicit val listFunctor: Functor[List]; implicit val listApplicative: Applicative[List]
, because then the compiler is confused when you ask for implicit param: Functor[List]
. implicit val listFunctor: Functor[List]; implicit val listApplicative: Applicative[List]
,因为当您要求implicit param: Functor[List]
时,编译器会感到困惑。 You should only have the latter. 您应该只有后者。 What you're trying to do is then nonsensical, because you're defining the Functor
instance for F
in terms of itself (because the Applicative[F]
should be the Functor[F]
), and you end up with two Functor[Seq]
s regardless. 然后,您尝试做的事情是荒谬的,因为您是根据F
本身定义F
的Functor
实例的(因为Applicative[F]
应该是 Functor[F]
),最后得到两个Functor[Seq]
不管。
What you can do is implement fmap
in terms of pure
and fapply
: 你可以做的是落实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]
}
Then remove the Functor[Seq]
instance and keep your Applicative[Seq]
the way it is (or override fmap
if you want). 然后删除Functor[Seq]
实例,并保持Applicative[Seq]
的状态fmap
(或根据需要覆盖fmap
)。 You have a different problem now, being that implicit search gets a bit turned around, as the Functor[Seq]
instance is actually in object Applicative
, but fixing implicit resolution is less onerous than enforcing the consistency of separate Functor
and Applicative
instances. 现在您遇到了另一个问题,因为Functor[Seq]
实例实际上在object Applicative
,所以隐式搜索需要解决一些问题,但是解决隐式分辨率要比强制执行单独的Functor
和Applicative
实例的一致性少。 In this case, where Seq
is a type whose companion object you cannot control, cats
, at least, does something like 在这种情况下,如果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 ...
}
FYI: I suggest currying your typeclass methods 仅供参考:我建议使用您的类型类方法
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]
and it may be nice to have a flip fapply
in ApplicativeOps
在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.