2015-08-27 44 views
8

假設我想穿越案例類通用表示所描述here使用無形的標籤與LabelledGenerics

我定義了一些類型類描述字段:

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

定義了一些實例:

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

和一般用戶:

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

所以,現在我可以寫

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

,並得到

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

現在我想用shapeless標籤來定義一些字段元數據:

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

所以Described(invisible(0.5))現在成功地生產

res2: String = 0,500[invisible]

但隨着重新定義

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

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

產生編譯錯誤:

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

我相信這種類型的X with Tag[Y] with KeyTag[K,X]不識別爲FieldType[S, X],但不能猜測如何解決它。

如何定義合適的LeftFolder這種情況?

回答

0

您的問題根本不涉及shapeless。它可以實際簡化爲:

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可以被 「表示」 爲Double with Invisible。請注意,Double with Invisible <: Double

當編譯器試圖得到一個隱含的Described[Double with Invisible]它正確地抱怨發散的隱式擴展:doubleDescribedinvisibleDescribed

再回到您的原代碼,一個簡單的辦法可能是剛剛改寫invisibleDescribed爲:

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