【问题标题】:Type resolution with higher kinded types and implicits具有更高种类的类型和隐式的类型解析
【发布时间】:2014-10-29 12:47:54
【问题描述】:

我正在尝试编写一个值类来为任何实现 Seq[_] 的东西添加功能,并允许它进行返回 Future[_] 的批处理调用(具体来说,我正在使用它进行批处理 REST 调用)。

final class BatchedList[A, C[X] <: Seq[X]](val targetList: C[A]) extends AnyVal {

  def batchRequests[B](batchSize: Int)(runner: Seq[A] => Seq[Future[Either[Result, B]]])
    (implicit bf: CanBuildFrom[C[A], Either[Result, B], C[Either[Result, B]]]): Future[Either[Result, C[B]]] = {
      targetList.grouped(batchSize).foldLeft(Future.successful(bf(targetList))) { (results, set) =>
        results flatMap { responses =>
          Future.sequence(runner(set)).map(responses ++=)
        }
      } map {
        _.result().sequenceU
      }
    }
  }

但是,我无法编译它。我不断收到编译器错误

value sequenceU is not a member of type parameter C[Either[play.api.mvc.Result,B]]

我已经导入了scalaz._Scalaz._,并且我知道他们已经为我的用例提供了Traverse[_](在这个例子中是List[_])。我很确定这是类型的某种隐含解决问题,但我对如何继续解决它感到困惑。

【问题讨论】:

    标签: scala scalaz


    【解决方案1】:

    我相信这是因为 Scalaz 没有为 Seq 提供类型类实例,而是为 IndexedSeqList 提供类型类实例。因此,您需要自己提供 Traverse 实例(注意附加的隐式参数 CbatchRequests):

    final class BatchedList[A, C[X] <: Seq[X]](val targetList: C[A]) extends AnyVal {
      def batchRequests[B](batchSize: Int)(runner: Seq[A] => Seq[Future[Either[Result, B]]])
        (implicit bf: CanBuildFrom[C[A], Either[Result, B], C[Either[Result, B]]], C: Traverse[C]): Future[Either[Result, C[B]]] =
          targetList.grouped(batchSize).foldLeft(Future.successful(bf(targetList))) { (results, set) =>
            results flatMap { responses =>
              Future.sequence(runner(set)).map(responses ++=)
            }
          } map {
            _.result().sequenceU
          }
    }
    

    如您所见,这将返回一个与提供为C的类型相对应的序列类型:

    scala> def run[A](s: Seq[A]): Seq[Future[Either[Result, A]]] =
         |   s.map(i => Future.successful(Right(i)))
    run: [A](s: Seq[A])Seq[scala.concurrent.Future[Either[Result,A]]]
    
    scala> :t new BatchedList(List(1,2,3)).batchRequests(1)(run)
    scala.concurrent.Future[Either[Result,List[Int]]]
    
    scala> :t new BatchedList(Vector(1,2,3)).batchRequests(1)(run)
    scala.concurrent.Future[Either[Result,scala.collection.immutable.Vector[Int]]]
    

    如果您总是希望它返回 Seq,则只需简单的向上转换即可。

    【讨论】:

    • 但是_.result()的结果不是Seq[_],而是C[_],在List上调用时应该是List[_]
    • 当在List 上调用时,它确实返回了Future[Either[Result, List[B]]]——这不是你想要的吗?我已经编辑了我的答案来说明这一点。
    • 知道了,我错过了 implicit C: Traverse[C] 的添加。那么我想我的问题是,为什么需要那个额外的参数?既然我已经在与函数声明相同的范围内使用Scalaz._ 导入了所有隐式,为什么我需要在方法签名中添加它?我想我对隐式解析规则感到困惑。
    • 我不是这方面的专家,但我对原因的理解是,正如您所写,您已经告诉它targetListC[A] 其中@987654341 @。因此,即使编译器知道CSeqsome 子类型,它也不知道是哪一个,因为Seq 没有Traverse,但仅适用于一些它的子类型,没有合适的实例可以找到。例如,当CList 时,确实有一个Traverse[List] 实例,但是在这个方法中Scala 不知道 CList
    猜你喜欢
    • 2011-04-18
    • 2018-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    • 2012-08-25
    相关资源
    最近更新 更多