EugeneMi
EugeneMi

Reputation: 3575

Can type classes be applied to sealed traits?

Is it possible to have a type class that is applied to a sealed trait?

The following sealed Trait

sealed trait MyType
object Type1 extends MyType
object Type2 extends MyType
case class Type3(i:Int) extends MyType

And I want to enrich the trait with a 'show' function that can be represented using the following type class

trait Show[A] { def show(a: A): String }

And I would like to us it in a function that accepts a trait as an input

def show[A :< MyType](a: A)(implicit sh: Show[A]) = sh.show(a) // Will not compile

Usually I could do something like

 implicit val type3CanShow: Show[Type3] =
new Show[Type3] {
  def show(t: Type3): String = s"show ${t.i}"
}

To get this to work I have 2 problems: 1) How do I define the type class on a object instead of a class (i.e Type1 and Type 2) 2) How do I get it to accept work on a trait, and make sure that the type class is provided for 3 products of the sealed trait

To solve 2 I could do something like (doen't compile - assumes all 3 were case classes)

def show[A :< MyType](a: A)(implicit sh: Show[A]) =
  a match { 
     case t: Type1 =>  sh.show(t)
     case t: Type2 =>  sh.show(t)
     case t: Type3 =>  sh.show(t)
  }

UPDATE: @thesamet solved 1. However, I would still like a better way to do 2. Running code like this, without having to add the pattern matching from above def doSomething(t: MyType) = { show(t) }

Upvotes: 0

Views: 461

Answers (1)

thesamet
thesamet

Reputation: 6582

The code you pasted

def show[A :< MyType](a: A)(implicit sh: Show[A]) = sh.show(a) // Will not compile

does not compile since it should be <: and not :< to specify MyType as the upperbound for A. The following does compile:

def show[A <: MyType](a: A)(implicit sh: Show[A]) = sh.show(a)

To define an implicit value for Type1 you have to specify the type of the singleton object:

implicit val ShowType1 = new Show[Type1.type] {
  def show(a: Type1.type) = "Type1"
}

Similarly for Type2:

implicit val ShowType2 = new Show[Type2.type] {
  def show(a: Type2.type) = "Type2"
}

Try it!

println(show(Type1))

Upvotes: 1

Related Questions