0

I am trying to define an instance of Show (from cats 0.9) that can be used for all members of an ADT as follows:

import $ivy.`org.typelevel::cats:0.9.0`, cats.Show

sealed abstract class Colour(val name: String)

implicit val ColourShow = new Show[Colour] {
  def show(c: Colour) = c.name
}

object Colour {
  object Red extends Colour("Red")
  object Blue extends Colour("Blue")
}

import Show._

println(Colour.Red.show)

An applicable instance cannot be found for Red, however:

Compiling /Users/Rich/Projects/worksheets/fp-patterns/Colours.sc
/Users/Rich/Projects/worksheets/fp-patterns/Colours.sc:16: value show is not a member of object ammonite.$file.Colours.Colour.Red
val res_5 = println(Colour.Red.show)
                               ^
Compilation Failed

Is it possible to use typeclasses in this way? I am trying to avoid having to define a separate instance for each concrete instanct of Colour.

Rich Ashworth
  • 1,995
  • 4
  • 19
  • 29

2 Answers2

1

I think you're mistaking what's happening here. The implicit you've defined does actually work for the instances.

eg.

ColourShow.show(Colour.Red)

If you want to be able to call show() on an instance of a Colour, without any arguments, you'll need to provide a definition of a trait that has a method show, which takes no arguments, and an implicit conversion from Colour to that trait.

Ren
  • 3,395
  • 2
  • 27
  • 46
1

Additionally to what people have pointed out, you'll need to import import cats.implicits._

see a working example in: https://scastie.scala-lang.org/d1egoaz/LVaJEccDSeas9VmzHqf1ug/1

You can also use the shorter version to create a Show instance for Colour:

implicit val colourShow: Show[Colour] = Show.show[Colour](_.name)
Diego Alvarez
  • 2,837
  • 1
  • 17
  • 16