3

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)
               ^
Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

1 Answers1

4

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).

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • Thanks, Travis. And the `Show` in `Shows.show` is the [object](http://docs.typelevel.org/api/scalaz/nightly/index.html#scalaz.Show$), not the `trait`, I see. Is this approach, i.e. using the `Show#shows` definition of `Show[Gender]`, the idiomatic way to define `Show[A]`? – Kevin Meredith Jun 19 '15 at 19:56
  • `Show.shows` is a convenience method that allows you to create a `Show` instance for `A` from a function `A => String`. You could also use `new Show[A] { ... }`—it'd just be a little more verbose and less idiomatic. – Travis Brown Jun 19 '15 at 19:59
  • 1
    If you define the implicit val inside the Gender companion object then the compiler will always find it even when it's not explicitly imported – Daenyth Jun 19 '15 at 20:37
  • @Daenyth Yeah, worth noting (and it [even works if the object is private](http://stackoverflow.com/q/30856740/334519)). – Travis Brown Jun 19 '15 at 21:04