Załóżmy chciałbym przechodzić klasy przypadek ogólny reprezentacji jak opisano hereKorzystanie bezkształtne tagi z LabelledGenerics
Mam zdefiniowane jakieś typeclass opisania pola:
trait Described[X] extends (X => String)
object Described{
def apply[X](x: X)(implicit desc: Described[X]) = desc(x)
}
Defined pewną instancję:
implicit object DoubleDescribed extends Described[Double]{
def apply(x: Double) = x.formatted("%01.3f")
}
Ogólny użytkownik:
import shapeless._
import shapeless.labelled.FieldType
import shapeless.ops.hlist.LeftFolder
object DescrFolder extends Poly2{
implicit def field[X, S <: Symbol](implicit desc: Described[X],
witness: Witness.Aux[S]):
Case.Aux[Seq[String], FieldType[S, X], Seq[String]] =
at[Seq[String], FieldType[S, X]](
(descrs, value) => descrs :+ f"${witness.value.name}: ${desc(value)}")
}
def describe[T <: Product, Repr <: HList](struct: T)
(implicit lgen: LabelledGeneric.Aux[T,Repr],
folder: LeftFolder.Aux[Repr, Seq[String], DescrFolder.type, Seq[String]]
): String = {
val repr = lgen.to(struct)
val descrs = folder(repr,Vector())
descrs.mkString(struct.productPrefix + "{", ",", "}")
}
Więc teraz mogę napisać
case class Point(x: Double, y: Double, z: Double)
describe(Point(1,2,3.0))
i dostać
res1: String = Point{x: 1,000,y: 2,000,z: 3,000}
Teraz chciałbym określić pewne pole metadanych za pomocą shapeless
tagi:
import tag._
trait Invisible
val invisible = tag[Invisible]
implicit def invisibleDescribed[X](implicit desc: Described[X])
: Described[X @@ Invisible] =
new Described[X @@ Invisible]{
def apply(x: X @@ Invisible) = desc(x: X) + "[invisible]"
}
tak Described(invisible(0.5))
teraz pomyślnie produkuje
res2: String = 0,500[invisible]
Ale z przedefiniowana
case class Point(x: Double, y: Double, z: Double @@ Invisible)
describe(Point(1,2,invisible(3.0)))
daje błąd kompilacji:
Error: diverging implicit expansion for type
LeftFolder.Aux[this.Out,Seq[String],DescrFolder.type,Seq[String]]
starting with methodinvisibleDescribed
in class ...
Przypuszczam, że typ X with Tag[Y] with KeyTag[K,X]
nie identyfikuje jako FieldType[S, X]
ale nie mógł odgadnąć, jak to naprawić.
Jak zdefiniować prawidłową dla takiej sytuacji LeftFolder
?