Reputation: 9540
I currently have the following (not type safe) api which I'm trying to redesign in a typesafe way:
import cats.instances.list._
import cats.syntax.functorFilter._
sealed trait EnumType
case object A extends EnumType
case object B extends EnumType
case object C extends EnumType
sealed abstract class TypeInfo[T <: EnumType](val enumType: T)
case class Ainfo() extends TypeInfo(A)
case class Ainfo2() extends TypeInfo(A)
case class Binfo() extends TypeInfo(B)
case class Cinfo() extends TypeInfo(C)
//This is the function implemented in a not typesafe way
def filterByEnumType[T <: EnumType: ClassTag](lst: List[TypeInfo[_]]): List[TypeInfo[T]] = {
lst mapFilter { info =>
info.enumType match {
case _: T => Some(info.asInstanceOf[TypeInfo[T]]) //not type safe
case _ => None
}
}
}
filterByEnumType[A.type](List(Ainfo(), Binfo(), Ainfo2(), Cinfo())) //List(Ainfo(), Ainfo2())
Is there an approach to implement it typesafely? Are typemembers useful for such task or probbably shapeless
can be used for that?
Upvotes: 2
Views: 124
Reputation: 3965
I came up with two related approaches with shapeless. I'm not sure either will exactly meet your needs because they depend on having all the types of the elements of the list known ahead of time.
Assuming you have this stuff:
import shapeless._
import shapeless.ops.hlist._
type HType = TypeInfo[A.type] :: TypeInfo[B.type] :: TypeInfo[A.type] :: TypeInfo[C.type] :: HNil
val hlist: HType = Ainfo() :: Binfo() :: Ainfo2() :: Cinfo() :: HNil
You can use filter on the HList
directly:
hlist.filter[TypeInfo[A.type]] // Ainfo() :: Ainfo2() :: HNil
If you want to avoid explicitly specifying TypeInfo
in the filter call you can modify your filter function (but now you're required to give the HList type -- this can be worked around using a proxy class):
def filterByEnumType[T <: EnumType, L <: HList](
list: L
)(implicit filter: Filter[L, TypeInfo[T]]): filter.Out = {
filter.apply(list)
}
filterByEnumType[A.type, HType](hlist) // Ainfo() :: Ainfo2() :: HNil
Upvotes: 2