Search code examples
scalatypeclassfunctor

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.


Solution

  • 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])