具有更高种类类型和方差的scala类型类

时间:2018-06-29 22:03:58

标签: scala types typeclass higher-kinded-types

我有一个与此问题非常相似的问题:Scala higher kinded type variance

但是,这稍有不同,它不会编译(scala 2.11.8)。

基本思想是采用提供的“事物”数组。如果数组为空,则返回某种类型的默认值(例如BooleanOptionList[Int]),否则对数组进行操作并产生结果。结果和默认值具有相同的类型。

我面临的挑战是使其能够在广泛的结果类型中使用。

这是一个人为的例子:

  trait NullGuard[F[_]] {
    def nullGuard[A, B](arr: Array[A], default: F[B])(expr: => F[B]): F[B] =
      if (arr == null || arr.length == 0) default else expr
  }

让我们创建一个返回Option的实现:

  implicit def optionNullGuard[F[X] <: Option[X]]: NullGuard[F] = new NullGuard[F]() {}

上面的代码确实可以编译,但是下面的尝试不使用上面的类型类:

  def returnsOption[F[_], A, B](arr: Array[A])(implicit ng: NullGuard[F]): Option[B] = {
    ng.nullGuard(arr, None) {
      // sample work
      if (arr.length % 2 == 0) Option(1) else None
    }
  }

我收到以下编译错误:

type mismatch;
found   : None.type
required: F[?]
  ng.nullGuard(arr, None){

我该如何使用它?如果有的话,我也愿意采用另一种方法。

1 个答案:

答案 0 :(得分:5)

由于类型类没有任何抽象方法,因此可以用单个多态nullGuard方法代替它:

def nullGuard[A, B]
  (arr: Array[A], defaultValue: B)
  (processArray: Array[A] => B)
: B = if (arr == null || arr.isEmpty) defaultValue else processArray(arr)

似乎也不再需要类型更高的类型参数F:提供一种适用于任何B作为返回类型的方法,而不仅仅是{{1} }。

这是您人为的,稍作修改的示例:如果数组中元素的数量为偶数,则从数组中提取最后一个值:

F[B]

输出:

for (example <- List[Array[Int]](null, Array(), Array(42), Array(1, 42))) {
  val lastAtEvenIndex = nullGuard[Int, Option[Int]](example, Some(0)) { 
    a => if (a.size % 2 == 0) Option(a.last) else None
  }
  println(lastAtEvenIndex)
}

对于长度不均匀的数组,它返回Some(0) Some(0) None Some(42) ,并将空/空数组视为将None作为“最后一个”元素。


完整示例为单个代码段,其中0为默认值:

None

打印:

def nullGuard[A, B]
  (arr: Array[A], defaultValue: B)
  (processArray: Array[A] => B)
: B = if (arr == null || arr.isEmpty) defaultValue else processArray(arr)


for (example <- List[Array[Int]](null, Array(), Array(42), Array(1, 42))) {
  val lastAtEvenIndex = nullGuard[Int, Option[Int]](example, None) { 
    a => if (a.size % 2 == 0) Option(a.last) else None
  }
  println(lastAtEvenIndex)
}