代码之家  ›  专栏  ›  技术社区  ›  Cheetah

无形状hlist隐式分解-发散隐式展开

  •  0
  • Cheetah  · 技术社区  · 6 年前

    这真让我恼火。我得到了 diverging implicit expansion for type Meta[Field2 :: HNil] 我尝试编译以下内容的错误:

    case class Field() extends StaticAnnotation
    case class Group() extends StaticAnnotation
    case class Message() extends StaticAnnotation
    
    @Field case class Field1(value: String)
    @Field case class Field2(value: String)
    @Field case class Field3(value: String)
    @Group case class Group1(field1: Field1, field2: Field2)
    @Message case class Message1(field3: Field3, group1: Group1)
    
    trait Meta[T]
    
    object Meta {
      implicit val hNil: Meta[HNil] = new Meta[HNil] {}
      implicit def field[TField](implicit a: Annotation[Field, TField]): Meta[TField] = new Meta[TField] {}
      implicit def hcons[Head, Tail <: HList](implicit h: Meta[Head], t: Meta[Tail]) : Meta[H :: T] = new Meta[H :: T] {}
      implicit def group[TGroup, ParamList <: HList](implicit a: Annotation[Group, TGroup], g: Generic.Aux[TGroup, ParamList], p: Meta[ParamList]): Meta[TGroup] = new Meta[TGroup] {}
      implicit def message[TMessage, ParamList <: HList](implicit a: Annotation[Message, TMessage], g: Generic.Aux[TMessage, ParamList], p: Meta[ParamList]): Meta[TMessage] = new Meta[TMessage] {}
    }
    
    object TestApp extends App {
      // throws compile exception here...
      implicitly[Meta[Message1]]
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Kolmar    6 年前

    考虑扩张的过程 Meta[Message1] :

    • 膨胀时 元[消息1 ] 具有 message 编译器需要 Meta[Field3 :: Group1 :: HNil]
    • 稍后,当扩展时 Meta[Group1] 具有 group 它需要 Meta[Field1 :: Field2 :: HNil]

    编译器发现,在这个分支中,它已经扩展了类型构造函数 :: 至少具有相同的复杂性(即,在 HList )所以它假设,这个扩展分支产生一个无限循环,并报告隐式散度。

    为了防止这种行为,你可以使用 shapeless.Lazy . 从文档中:

    包装延迟计算的值。在隐式过程中也绕过了循环 如下图所示,搜索或错误的隐含分歧,并保持 相应的隐式值延迟。

    为了解决这个问题,你可以总结一下 Lazy 扩大 Head 在里面 hcons :

    implicit def hcons[Head, Tail <: HList](implicit 
      h: Lazy[Meta[Head]], 
      t: Meta[Tail]
    ): Meta[Head :: Tail] = 
      new Meta[Head :: Tail] {}
    

    通常你应该包起来 懒惰 头部的扩张 HLIST Coproduct 规则,以及扩展 Repr 在里面 Generic 规则。我想,在这里不需要后者,因为你必须通过 HCONS 规则,已经有了 懒惰 ,从一个 Group Message 对另一个)。