Scala Nat和x27之和的编译时检查;s

Scala Nat和x27之和的编译时检查;s,scala,shapeless,Scala,Shapeless,我试图编写一个类型类,SumEq5,这样它的HListtype参数的前两个字段加起来就是5: trait SumEq5[A] object SumEq5 { def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev implicit def sumEq5Ev[L <: HList, A <: Nat, B <: Nat]( implicit hcons: IsHCons.Aux[L, A,

我试图编写一个类型类,
SumEq5
,这样它的
HList
type参数的前两个字段加起来就是
5

trait SumEq5[A]
object SumEq5 {
  def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev

  implicit def sumEq5Ev[L <: HList, A <: Nat, B <: Nat](
    implicit hcons: IsHCons.Aux[L, A, B :: HNil],
             ev: Sum.Aux[A, B, _5]
  ): SumEq5[L] = new SumEq5[L] {}
}
trait SumEq5[A]
对象SumEq5{

def apply[L我只有一个部分答案供您参考,即(变通)解决方案,但不了解为什么原始解决方案不能按预期工作

似乎你不能直接要求一个
IsHCons.Aux[L,a,B::HNil]
,你需要零碎地做:

  • IsHCons.Aux[L,A,L2]
    ,然后
  • IsHCons.Aux[L2,B,HNil]
  • 因此,本文件汇编:

    import shapeless._, nat._, ops.hlist._, ops.nat._
    
    trait SumEq5[A]
    object SumEq5 {
      def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev
    
      implicit def sumEq5Ev[L <: HList, L2 <: HList, A <: Nat, B <: Nat](
        implicit hcons0: IsHCons.Aux[L, A, L2],
                 hcons: IsHCons.Aux[L2, B, HNil],
                 ev: Sum.Aux[A, B, _5]
      ): SumEq5[L] = new SumEq5[L] {}
    }
    
    object T {
      def main(args: Array[String]): Unit = {
        SumEq5[_0 :: _5 :: HNil]
      }
    }
    
    import shapeless.\uu,nat.\uu,ops.hlist.\uu,ops.nat_
    性状表5[A]
    对象SumEq5{
    
    def apply[LDale Wijnand和Marcus Henry指出了正确的方向,如果你想推广到任意长度的
    HList
    s,但是如果你真的只想容纳两个元素
    HList
    s,那么下面是一个相当简单的解决方案

    scala> import shapeless._, nat._, ops.nat._
    import shapeless._
    import nat._
    import ops.nat._
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    trait SumEq5[A]
    
    object SumEq5 {
      def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev
    
      implicit def sumEq5AB[A <: Nat, B <: Nat]
        (implicit ev: Sum.Aux[A, B, _5]): SumEq5[A :: B :: HNil] =
          new SumEq5[A :: B :: HNil] {}
    }
    
    // Exiting paste mode, now interpreting.
    
    defined trait SumEq5
    defined object SumEq5
    
    scala> SumEq5[_0 :: _5 :: HNil]
    res0: SumEq5[_0 :: _5 :: HNil]] = SumEq5$$anon$1@658c5e59
    

    trait是空的,那么为什么不干脆
    newsumeq5[L]
    ?这很好,但它对我的输入不起作用,不是吗?当人们第一次学习使用递归或归纳类型时,我经常看到这种情况。编译器需要分步进行。Kevin正在尝试获取a::B::HNil的实例,而不首先拥有B::HNil的实例,而不首先拥有HNil的实例。这里的解决方案是回避需要通过添加一个IsHCons层来进行归纳过程。要进行归纳,你需要证明B::HNil小于或等于5,然后A::B::HNil等于5,在两个隐式def中。谢谢,Dale和Marcus!这个回答和评论肯定帮助我了解了更多。事实上,要简单得多。不过,我会假设这个想法就是句柄Any H包含2个或更多元素的列表,前两个元素的总和为5。更新后也可以捕获该案例。哦,是的,杜克。凯文,这是你的答案。
    import shapeless._, nat._, ops.hlist._, ops.nat._
    
    trait SumEq5[A]
    object SumEq5 {
      def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev
    
      implicit def sumEq5Ev[L1 <: HList, L2 <: HList, L3 <: HList, A <: Nat, B <: Nat](
        implicit hcons1: IsHCons.Aux[L1, A, L2],
                 hcons2: IsHCons.Aux[L2, B, L3],
                 ev: Sum.Aux[A, B, _5]
      ): SumEq5[L1] = new SumEq5[L1] {}
    }
    
    object T {
      def main(args: Array[String]): Unit = {
        SumEq5[_0 :: _5 :: HNil]
      }
    }
    
    scala> import shapeless._, nat._, ops.nat._
    import shapeless._
    import nat._
    import ops.nat._
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    trait SumEq5[A]
    
    object SumEq5 {
      def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev
    
      implicit def sumEq5AB[A <: Nat, B <: Nat]
        (implicit ev: Sum.Aux[A, B, _5]): SumEq5[A :: B :: HNil] =
          new SumEq5[A :: B :: HNil] {}
    }
    
    // Exiting paste mode, now interpreting.
    
    defined trait SumEq5
    defined object SumEq5
    
    scala> SumEq5[_0 :: _5 :: HNil]
    res0: SumEq5[_0 :: _5 :: HNil]] = SumEq5$$anon$1@658c5e59
    
    scala> import shapeless._, nat._, ops.nat._
    import shapeless._
    import nat._
    import ops.nat._
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    trait SumEq5[A]
    
    object SumEq5 {
      def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev
    
      implicit def sumEq5AB[A <: Nat, B <: Nat, T <: HList]
        (implicit ev: Sum.Aux[A, B, _5]): SumEq5[A :: B :: T] =
          new SumEq5[A :: B :: T] {}
    }
    
    // Exiting paste mode, now interpreting.
    
    defined trait SumEq5
    defined object SumEq5
    
    scala> SumEq5[_0 :: _5 :: HNil]
    res0: SumEq5[_0 :: _5 :: HNil]] = SumEq5$$anon$1@658c5e59