2015-08-27 9 views
8

Supponiamo mi piacerebbe attraversare caso classe rappresentazione generica come descritto hereuso dei nomi informi con LabelledGenerics

ho definito alcuni typeclass per descrivere i campi:

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

Definito qualche esempio:

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

E utente generale:

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

Così ora ho potuto scrivere

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

e ottenere

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

ora mi piacerebbe definire alcuni metadati campo utilizzando shapeless tags:

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

così Described(invisible(0.5)) ora con successo produce

res2: String = 0,500[invisible]

Ma con ridefinito

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

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

cede errore di compilazione:

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

Presumo che tipo X with Tag[Y] with KeyTag[K,X] non è l'identificazione come FieldType[S, X], ma non riuscivo a immaginare come risolvere il problema.

Come si può definire LeftFolder corretto per tale situazione?

risposta

0

Il problema non riguarda lo shapeless. Può essere effettivamente semplificata come:

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 può essere "rappresentato" come Double with Invisible. Si noti che Double with Invisible <: Double.

Quando il compilatore tenta di ottenere un numero implicito Described[Double with Invisible], si lamenta correttamente dell'espansione implicita divergente: doubleDescribed e invisibleDescribed.

Tornando al tuo codice originale, una soluzione semplice potrebbe essere quella di riscrivere solo invisibleDescribed come:

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