scala - Creating a type class instance for a sealed trait -
say have 'wide' sealed class hierarchy:
sealed trait alphabet case class a(word: string) extends alphabet ... case class z(word: string) extends alphabet
and have type class instance defined each child class in hierarchy:
trait swearwordfinder[t <: alphabet] { def isswearword(x: t): boolean } val swearwordfindera = new swearwordfinder[a] { ... } ... val swearwordfinderz = new swearwordfinder[z] { ... }
is there way can define type class instance alphabet
trait without having implement pattern matching (as below)?
def isswearword(x: alphabet): boolean = x match { case a: => swearwordfindera.isswearword(a) ... case z: z => swearwordfinderz.isswearword(z) }
you can represent alphabet
shapeless coproduct
of a :+: b :+: ... :+: z :+: cnil
, if have swearwordfinder
instances a
, b
, ... , define instances cnil
, :+:
can swearwordfinder[alphabet]
using generic representation.
import shapeless._ trait swearwordfinder[t] { def isswearword(x: t): boolean } object swearwordfinder extends swearwordfinder0 { implicit def apply[t](implicit swf: swearwordfinder[t]): swearwordfinder[t] = swf implicit val cnilswearwordfinder: swearwordfinder[cnil] = new swearwordfinder[cnil] { def isswearword(t: cnil): boolean = false } implicit def coproductconsswearwordfinder[l, r <: coproduct](implicit lswf: swearwordfinder[l], rswf: swearwordfinder[r] ): swearwordfinder[l :+: r] = new swearwordfinder[l :+: r] { def isswearword(t: l :+: r): boolean = t.eliminate(lswf.isswearword, rswf.isswearword) } } trait swearwordfinder0 { implicit def genericswearwordfinder[t, g](implicit gen: generic.aux[t, g], swf: lazy[swearwordfinder[g]] ): swearwordfinder[t] = new swearwordfinder[t] { def isswearword(t: t): boolean = swf.value.isswearword(gen.to(t)) } }
now instances our letters :
sealed trait alphabet extends product serializable object alphabet { final case class a(word: string) extends alphabet final case class z(word: string) extends alphabet } implicit val swfa = new swearwordfinder[alphabet.a] { def isswearword(a: alphabet.a) = a.word == "apple" } implicit val swfz = new swearwordfinder[alphabet.z] { def isswearword(z: alphabet.z) = z.word == "zebra" }
and can swearwordfinder[alphabet]
:
def isbadword[t](t: t)(implicit swft: swearwordfinder[t]): boolean = swft.isswearword(t) val a1: alphabet = alphabet.a("apple") val z2: alphabet = alphabet.z("zorro") val z3: alphabet = alphabet.z("zebra") isbadword(a1) // true isbadword(z2) // false isbadword(z3) // true
like mentioned in comment: beware of si-7046. alphabet
ast needs in project on project swearwordfinder
depends or in package compiled before package type class derivation alphabet
.
Comments
Post a Comment