Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 467
thlim Avatar asked Oct 17 '25 13:10

thlim


2 Answers

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.

like image 133
Dmytro Mitin Avatar answered Oct 20 '25 03:10

Dmytro Mitin


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])
like image 27
Mario Galic Avatar answered Oct 20 '25 04:10

Mario Galic



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!