Search code examples
scalainheritancescalazgadtscala-cats

Scala GADT instance Functor


In Haskell I got:

data Foo a where
  Bar :: a -> Foo a
  Map :: (a -> b) -> Foo a -> Foo b

instance Functor Foo where
  fmap = Map

In Scala I came up with:

import cats.Functor

trait Foo[A]
case class Bar[A](t: A) extends Foo[A]
case class Map[A,B](fun: A => B,foo: Foo[A]) extends Foo[B]

implicit val fooFunctor: Functor[Foo] = new Functor[Foo] {
  def map[A,B](fa: Foo[A])(f: A => B) = Map(f,fa)
}

But Bar(40).map(_+2) gives me:

error: value map is not a member of Bar[Int]

I fairly new to Scala and don't know the way of inheritance that well.

What am I missing?


Solution

  • You need to upcast Bar(40) to Foo explicitly, and import the syntax implicits:

    import cats.syntax.functor._
    (Bar(40): Foo[Int]).map(_+2)
    

    You need the upcast because Scala will infer the type Bar[Int] for the expression Bar(40) and this then interferes with finding the appropriate implicit that adds the map method. For this reason you sometimes see helper methods in the companion object to do the upcast for you:

    object Foo {
      def bar[A](a: A): Foo[A] = Bar(a)
      // etc.
    }