I want to map case class Bonus[A: Numeric](amt: A)
over a Functor and it fails. The compilation error is
Error:(157, 69) could not find implicit value for evidence parameter of type Numeric[B] (No implicit Ordering defined for B.)
override def fmap[A, B](fa: Bonus[A])(f: A => B): Bonus[B] = Bonus(f(fa.amt))
In general, I want to fix the parameter type in Bonus
to numbers. How do I do fix that? Thanks
The code snippet,
trait Functor[F[_]] {
def fmap[A, B](fa: F[A])(f: A => B): F[B]
}
def fmap[A, B, F[_]](fa: F[A])(f: A => B)(implicit ev: Functor[F]): F[B] = ev.fmap(fa)(f)
case class Bonus[A: Numeric](amt: A)
implicit val bonusFunctor = new Functor[Bonus] {
override def fmap[A, B](fa: Bonus[A])(f: A => B): Bonus[B] = Bonus(f(fa.amt)) // error
}
fmap(Bonus(123))(_ * 2)
Thank you Mario & Dmytro for your answers.
Dmytro, your answer is precisely as what I found at https://users.scala-lang.org/t/how-to-add-type-constraint-to-functors-map-function/2055 . It makes sense that either I drop the constraint or I use a constraint Functor. I accepted Mario's answer because it shows me an alternative solution because it is not possible with Functor.
Instance of Functor
type class can be defined not for any type constructor.
The fact that type constructor F[_]
has instance of type class Functor
means that for any A
, B
, having a function A => B
, you know how to transform F[A]
to F[B]
.
But how to transform Bonus[A]
to Bonus[B]
for any A
, B
?
Types Bonus[A]
, Bonus[B]
make sense for any A
, B
, even if they are not Numeric
, but creating new instance of Bonus[B]
via constructor makes sense only for B: Numeric
.
Either remove context bound Numeric
in case class Bonus[A: Numeric](amt: A)
or Bonus
is not a Functor
.
If you define your own type class
trait NumericFunctor[F[_]] {
def fmap[A: Numeric, B: Numeric](fa: F[A])(f: A => B): F[B]
}
it will be not the standard functor over category of types but a custom functor over category of Numeric
types.
Try
trait GFunctor[F[_], G[_]] {
def fmap[A, B](fa: F[A])(f: A => B)(implicit ga: G[A], gb: G[B]) : F[B]
}
def fmap[A, B, F[_], G[_]](fa: F[A])(f: A => B)(implicit ev: GFunctor[F, G], ga: G[A], gb: G[B]): F[B] = ev.fmap(fa)(f)
case class Bonus[A: Numeric](amt: A)
implicit val bonusFunctor = new GFunctor[Bonus, Numeric] {
override def fmap[A, B](fa: Bonus[A])(f: A => B)(implicit numA: Numeric[A], numbB: Numeric[B]): Bonus[B] = Bonus(f(fa.amt))
}
fmap(Bonus(123))(_ * 2)
which outputs
res0: Bonus[Int] = Bonus(246)
Note how we have made our typeclass solution aware of further bounds on A
and B
via
(implicit ga: G[A], gb: G[B])
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.