2017-04-12 2 views
0

Je voudrais définir un LabelledGeneric sans forme qui ignore un (ou plusieurs) champs lors de la conversion en HList; lors de la conversion du HList de nouveau il devrait substituer une valeur définie par l'utilisateur. Le but est de pouvoir écrire quelque chose comme ceci:Shapeless LabelledGeneric mais en ignorant certains champs

case class Foo(i: Int, s: String) 
val foo = Foo(123, "Hello") 

val gen = LabelledGeneric[Foo].ignoring('i)(defaultValue = -1) 
val hlist = gen.to(foo) 
// "Hello" :: HNil 

val foo2 = gen.from(hlist) 
assert(foo2 == Foo(-1, "Hello")) 

C'est ce que j'ai jusqu'à présent. Il compile, mais je ne peux pas obtenir les types de s'aligner correctement pour la résolution implicite lorsque je tente de l'utiliser:

implicit class IgnoringOps[T](orig: LabelledGeneric[T]) { 
    def ignoring[Orig <: HList, V, Ign <: HList](k: Witness)(defaultValue: V)(implicit 
    gen: LabelledGeneric.Aux[T, Orig], 
    rem: Remover.Aux[Orig, FieldType[k.T, V], Ign], 
    upd: Updater.Aux[Ign, FieldType[k.T, V], Orig]): LabelledGeneric[T] = { 
    new LabelledGeneric[T] { 
     override type Repr = Ign 
     override def to(t: T): Ign = rem(gen.to(t)) 
     override def from(r: Ign): T = gen.from(upd(r, field[k.T](defaultValue))) 
    } 
    } 
} 

Quelqu'un peut-il faire la lumière sur ce que je fais mal?

Répondre

0

Cela devrait fonctionner comme prévu (selon votre exemple):

implicit class IgnoringOps[T, L <: HList](gen: LabelledGeneric.Aux[T, L]) { 
    def ignoring[V, I <: HList, H <: HList](k: Witness)(v: V)(implicit 
     rem: Remover.Aux[L, k.T, (V, I)], 
     upd: Updater.Aux[I, FieldType[k.T, V], H], 
     ali: Align[H, L] 
    ): LabelledGeneric[T] = new LabelledGeneric[T] { 
     override type Repr = I 

     //`rem` is implicitly used there 
     override def to(t: T): I = gen.to(t) - k 

     //`upd` and `ali` are implicitly used there 
     override def from(r: I): T = gen.from(r + field[k.T](v)) 
    } 
    } 

Notes:

  • paramètre implicite Retirées gen: LabelledGeneric.Aux[T, L] de ignoring, vous pouvez tirer parti de paramètre de classe implicite orig;
  • Utilisé - et + méthodes de RecordOps au lieu d'utiliser explicitement rem et upd;
  • Mis à jour remimplicit parameter de Remover.Aux[L, FieldType[k.T, V], I], à Remover.Aux[L, k.T, (V, I)];
  • Aide intermédiaire supplémentaire H <: HList;
  • Mis à jour upd paramètre implicite, utilisant l'aide intermédiaire précitée, de Updater.Aux[I, FieldType[k.T, V], L] à Updater.Aux[I, FieldType[k.T, V], H];
  • Ajouté ali demande implicitement pour l'alignement de H et L: ali: Align[H, L]
+0

Aha! Il me manquait le 'Align' implicite, que j'avais oublié (j'ai tendance à penser à' record's comme Maps non ordonné, mais bien sûr l'ordre des choses quand vous reconstruisez l'instance de classe de cas). Je vous remercie :) –