2015-08-27 10 views
8

Angenommen, ich möchte generische Darstellung Fallklasse zu durchqueren als here beschriebenVerwendung formlos Tags mit LabelledGenerics

ich einige typeclass definiert haben Felder zu beschreiben:

:

trait Described[X] extends (X => String) 
object Described{ 
    def apply[X](x: X)(implicit desc: Described[X]) = desc(x) 
} 

einige Instanz definiert

implicit object DoubleDescribed extends Described[Double]{ 
    def apply(x: Double) = x.formatted("%01.3f") 
} 

Und allgemeiner Benutzer:

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 + "{", ",", "}") 
} 

So, jetzt könnte ich

case class Point(x: Double, y: Double, z: Double) 
describe(Point(1,2,3.0)) 

schreiben und

res1: String = Point{x: 1,000,y: 2,000,z: 3,000}

Jetzt bekomme ich möchte einige Feld Metadaten shapeless Tags definieren:

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]" 
    } 

so Described(invisible(0.5)) jetzt erfolgreich produziert

Aber mit neu definierten

case class Point(x: Double, y: Double, z: Double @@ Invisible) 

describe(Point(1,2,invisible(3.0))) 

ergibt Fehler Kompilation:

Error: diverging implicit expansion for type LeftFolder.Aux[this.Out,Seq[String],DescrFolder.type,Seq[String]] starting with method invisibleDescribed in class ...

ich diese Art vermuten X with Tag[Y] with KeyTag[K,X] nicht als FieldType[S, X] identifizieren konnte aber nicht erraten, wie es zu beheben. Wie kann man LeftFolder für eine solche Situation definieren?

Antwort

0

Ihr Problem betrifft nicht shapeless überhaupt. Es kann tatsächlich vereinfacht werden:

trait Described[T] 
trait Invisible 

implicit val doubleDescribed: Described[Double] = ??? 

implicit def invisibleDescribed[T](
    implicit desc: Described[T] 
): Described[T with Invisible] = ??? 

implicitly[Described[Double with Invisible]] 

Double @@ Invisible kann "vertreten", wie Double with Invisible werden. Beachten Sie, dass Double with Invisible <: Double.

Wenn der Compiler versucht, eine implizite Described[Double with Invisible] es richtig beschwert sich über divergierende implizite Expansion zu bekommen: doubleDescribed und invisibleDescribed.

zurück zu Ihrem ursprünglichen Code gehen, könnte eine einfache Lösung nur sein, neu zu schreiben invisibleDescribed wie:

implicit def invisibleDescribed[X, I <: X @@ Invisible](
    implicit desc: Described[X] 
): Described[I] = new Described[I]{ 
    def apply(x: I) = desc(x: X) + "[invisible]" 
}