I often find that I need to extract the type of a sealed trait before doing the same thing to each implementation:
sealed trait Trait
case class Foo() extends Trait
case class Bar() extends Trait
// ... lots of other implementations
// *must* take a `Trait`, not a `T <: Trait`
def thing(t: Trait): ??? = t match {
case f: Foo => // something with the instance and specific type
case b: Bar => // something with the instance and specific type
// ... same thing again for other implementations
}
for example
// typically provided by somebody else...
trait Thing[T] { def thingy: String }
implicit def thing[T]: Thing[T] = new Thing[T] { def thingy = "stuff" }
def thing(t: Trait): String = t match {
case Foo() => implicitly[Thing[Foo]].thingy
case Bar() => implicitly[Thing[Bar]].thingy
// ...
}
I'd like to reduce the boilerplate involved in doing this.
UPDATE: nowadays we'd use typeclass derivation via shapeless. e.g. https://github.com/fommil/shapeless-for-mortals
It turns out that you can use shapeless' polymorphic functions and co-product to do this:
object thing extends Poly1 {
implicit def action[T <: Trait: Thing] = at[T](
a => implicitly[Thing[T]].thingy
)
// magic that makes it work at the sealed trait level
def apply(t: Trait): String =
Generic[Trait].to(t).map(thing).unify
}
which can then be used like
println(thing(Foo(): Trait))
I'd like to make this easier to write via an abstract class (let's forget about passing on implicit parameters to action
for now), e.g.
abstract class MatchSealed[In, Out] extends Poly1 {
implicit def poly[T <: In] = at[T](action)
def action[T <: In](t: T): Out
import ops.coproduct.Mapper
def apply[R <: HList](in: In)(
implicit
g: Generic.Aux[In, R],
m: Mapper[this.type, R]
): Out = {
val self: this.type = this
g.to(in).map(self).unify
}
}
but this is failing with a missing Mapper[self.type, g.Repr]
on the final line. I don't know which implicit is missing, but I suspect it is the self.type. I really want to capture realisedSelf.type
but I don't know how to do that.
UPDATE: it turns out that it is not possible to obtain the Mapper
because it needs access to the realised object
Unable to map on HList
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With