编译时检查Nat的总和?

时间:2017-02-03 02:53:02

标签: scala shapeless

我尝试编写类型类SumEq5,以使其HList类型参数的前两个字段加起来为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] {}
}

但它似乎不起作用:

import shapeless._
import shapeless.nat._
import net.SumEq5

scala> SumEq5[_0 :: _5 :: HNil]
<console>:19: error: could not find implicit value for 
    parameter ev: net.SumEq5[shapeless.::[shapeless.nat._0,shapeless.::
       [shapeless.nat._5,shapeless.HNil]]]
       SumEq5[_0 :: _5 :: HNil]

请给我一个提示,说明为什么_0 :: _5 :: HNil没有证据证明其Nat等于5。

修改

根据shapeless's gitter中的Denis Rosca帮助更新了问题。

2 个答案:

答案 0 :(得分:3)

我只为您提供部分答案,即(解决方法)解决方案,但不理解为什么原件无法正常工作。

似乎你不能直接问<form class="login" action="file.php" method="POST"> .... ,你需要零碎地做:

  1. IsHCons.Aux[L, A, B :: HNil],然后
  2. IsHCons.Aux[L, A, L2]
  3. 因此,编译:

    IsHCons.Aux[L2, B, HNil]

    Miles Sabin's answer开始,可以调整以支持2个或更多元素的任何HList,其中前两个的总和为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[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]
      }
    }
    

答案 1 :(得分:3)

如果你想要推广到任意长度的MainActivity,Dale Wijnand和Marcus Henry指向正确的方向,但如果你真的只想容纳两个元素viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { int previousState; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { if (previousState == ViewPager.SCROLL_STATE_SETTLING && state == ViewPager.SCROLL_STATE_IDLE) { pagerAdapter.notifyDataSetChanged(); } previousState = state; } }); ,那么以下是一个相当简单的解决方案,

HList

这里的主要区别在于实例是为两个元素列表显式定义的,而不是一般为列表定义的,条件是存在列表中恰好有两个元素的证明。

根据Dale的更新,我们可以概括这一点以容纳HList至少有两个(而不是两个)元素,同样没有任何其他证人,

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