【问题标题】:Enforce upper bound for HList types at compile time在编译时强制 HList 类型的上限
【发布时间】:2016-07-04 07:59:29
【问题描述】:

我正在尝试为某些作为特征“可识别”的子类型的类型创建通用特征“回购”。我的计划是通过传递描述“可识别”子类型的通用 TypeTag[HList] 来实例化“回购”的实现者。

如何让编译器保证 HList 中传递的类型是 trait 'Identifiable' 的子类型?

这是我目前得到的:

    //All types in HList must extend Identifiable, how to enforce that at compile time?
    trait Repo {
      implicit val ltag: TypeTag[L] forSome {type L <: HList}
      ..
    }

    trait Identifiable {
      ..
    }

    case class Person(..) extends Identifiable
    case class Address(..)

    //This should compile
    class MyRepo 
      (implicit val ltag: TypeTag[Person :: HNil])
      extends Repo {
      ..  
    }

    //This should not
    class MyRepo 
      (implicit val ltag: TypeTag[Address :: HNil])
      extends Repo {
      ..  
    }
//HList can contain an unknown number of types

我看到了这个似乎相关的问题: Type inference on contents of shapeless HList 不同之处在于我没有 HList 的实现可以使用,所以不确定如何仅使用类型计算上限。

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/hlistconstraints.scala提供的HList上有一整套约束。

    你要找的可能是LUBConstraint。引用文档:

    类型类见证L 的每个元素都是B 的子类型。

    要使用,您只需要要求 LUBContraint[L, Identifiable] 的隐含证据。

    例如

    trait Repo[L <: HList] {
      implicit val ltag: TypeTag[L]
      implicit val ev: LUBConstraint[L, Identifiable]
    }
    
    trait Identifiable
    case class Person(name: String) extends Identifiable
    case class Address(street: String)
    
    type P = Person :: HNil
    class MyPersonRepo(implicit
      val ltag: TypeTag[P],
      val ev: LUBConstraint[P, Identifiable]
    ) extends Repo[P]
    
    
    type A = Address :: HNil
    class MyAddressRepo(implicit
      val ltag: TypeTag[A],
      val ev: LUBConstraint[A, Identifiable]
    ) extends Repo[A]
    
    new MyPersonRepo // this works
    new MyAddressRepo // this doesn't
    

    如果你愿意使用抽象类而不是 trait,你可以让一切变得更好

    abstract class Repo[L <: HList](implicit
      val ltag: TypeTag[L],
      val ev: LUBConstraint[L, Identifiable]
    )
    
    trait Identifiable
    case class Person(name: String) extends Identifiable
    case class Address(street: String)
    
    type P = Person :: HNil
    class MyPersonRepo extends Repo[P]
    
    type A = Address :: HNil
    class MyAddressRepo extends Repo[A]
    

    现在您在扩展类时会立即收到错误消息。

    【讨论】:

    • 将这些证据传递给实现者的特征的语法是什么?我无法将类型参数传递给 trait,所以我很难理解它..
    • @eirirlar 见上面的例子
    猜你喜欢
    • 2017-09-16
    • 1970-01-01
    • 2017-01-17
    • 1970-01-01
    • 1970-01-01
    • 2015-04-02
    • 1970-01-01
    • 1970-01-01
    • 2014-12-30
    相关资源
    最近更新 更多