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

Eri*_*rik 3 types scala typeclass higher-kinded-types

我有一个与此非常类似的问题:Scala更高的kinded类型方差

然而,这有点不同,嗯,它不编译(scala 2.11.8).

基本思想是采用一系列"事物".如果数组为空,返回某种类型的默认值(例如Boolean,Option,List[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
  }
Run Code Online (Sandbox Code Playgroud)

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

  implicit def optionNullGuard[F[X] <: Option[X]]: NullGuard[F] = new NullGuard[F]() {}
Run Code Online (Sandbox Code Playgroud)

以上编译,但以下尝试使用上述类型不会:

  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
    }
  }
Run Code Online (Sandbox Code Playgroud)

我得到以下编译错误:

type mismatch;
found   : None.type
required: F[?]
  ng.nullGuard(arr, None){
Run Code Online (Sandbox Code Playgroud)

我怎样才能让它发挥作用?如果有的话,我也会接受另一种方法.

And*_*kin 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)
Run Code Online (Sandbox Code Playgroud)

更高的kinded类型参数F似乎也不再需要:它不会花费你任何东西来提供一个适用于任何B返回类型的方法,而不仅仅是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)
}
Run Code Online (Sandbox Code Playgroud)

输出:

Some(0)
Some(0)
None
Some(42)
Run Code Online (Sandbox Code Playgroud)

它返回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)
}
Run Code Online (Sandbox Code Playgroud)

打印:

None
None
None
Some(42)
Run Code Online (Sandbox Code Playgroud)