Resolving Implicit for `Show` Typeclass Instance

613 views Asked by At

I'm trying to make Gender implement the Show typeclass.

scala> trait Gender extends Show[Gender]
defined trait Gender

scala> case object Male extends Gender
defined object Male

scala> case object Female extends Gender
defined object Female

Next, I defined a function that calls show on an implicit Show[A].

scala> def f[A : Show](x: A): String = implicitly[Show[A]].shows(x)
f: [A](x: A)(implicit evidence$1: scalaz.Show[A])String

Finally, I created an implicit class for Show[Gender]:

scala> implicit class GenderShows(g: Gender) extends Show[Gender] {
     |    g match {
     |      case Male   => "Male"
     |      case Female => "Female"
     |    }
     | }
defined class GenderShows

I tried it out, but it's not finding such an implicit:

scala> val male: Gender = Male
male: Gender = Male

scala> f(male)
<console>:20: error: could not find implicit value for 
     evidence parameter of type scalaz.Show[Gender]
              f(male)
               ^
1

There are 1 answers

4
Travis Brown On BEST ANSWER

This isn't really how type classes work. Instead of extending the type class in your class definition, you provide an instance for your type separately as an implicit value:

import scalaz._, Scalaz._

trait Gender
case object Male extends Gender
case object Female extends Gender

implicit val GenderShows: Show[Gender] = Show.shows {
  case Male   => "Male"
  case Female => "Female"
}

def f[A: Show](x: A): String = implicitly[Show[A]].shows(x)

And then:

scala> val male: Gender = Male
male: Gender = Male

scala> f(male)
res0: String = Male

This is one of the big advantages of type classes over subtyping—they decouple the definition of your data types from the definition of the operations you want to support on those types (nobody wants to have to change their inheritance hierarchy every time they need to support a new serialization library, for example).