简体   繁体   中英

Numeric Map Over With Functor

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)

Update 1

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM