函数参数的隐式解析

时间:2015-06-15 12:36:01

标签: scala implicit context-bound

我尝试在Scala中实现mergesort。我得到了以下内容:

def mergeSort[A: Ordering](as: List[A]): List[A] = as match {
  case Nil         => as
  case head :: Nil => as
  case _ => {
    val (l, r) = split(as)
    merge(mergeSort(l), mergeSort(r))
  }
}

def split[A](as: List[A]): (List[A], List[A]) = {
  def rec(todo: List[A], done: (List[A], List[A])): (List[A], List[A]) = todo match {
    case Nil          => done
    case head :: tail => rec(tail, (head :: done._2, done._1))
  }
  rec(as, (Nil, Nil))
}

def merge[A: Ordering](left: List[A], right: List[A]) = {
  def rec(left: List[A], right: List[A], done: List[A]): List[A] =
    (left, right) match {
      case (_, Nil) => rprepend(left, done)
      case (Nil, _) => rprepend(right, done)
      case (lh :: lt, rh :: rt) => if (implicitly[Ordering[A]].compare(lh, rh) <= 0)
        rec(lt, right, lh :: done)
        else rec(left, rt, rh :: done)
    }

  rec(left, right, Nil).reverse
}

def rprepend[A](prepend: List[A], as: List[A]): List[A] =
  prepend.foldLeft(as)((r, a) => a :: r)

这个问题不是关于低效逆转的猥亵数量,也不是关于尾递归的缺乏。相反,我注意到你可以通过传递类似的排序算法来概括mergesort:

def generalizedMergeSort[A: Ordering](as: List[A], sort: List[A] => List[A]): List[A] = as match {
  case Nil         => as
  case head :: Nil => as
  case _ => {
    val (l, r) = split(as)
    merge(sort(l), sort(r))
  }
}

然后我尝试将mergesort重新实现为

def mergesort[A: Ordering](as: List[A]): List[A] = {
  generalizedMergeSort(as, mergesort)
}

但是无法编译,找不到合适的Ordering[A]

[error] test.scala:17: No implicit Ordering defined for A.
[error]     generalizedMergeSort(as, mergesort)
[error]                              ^

作为一个微弱的尝试,我尝试了范围

def mergesort[A: Ordering](as: List[A]): List[A] = {
  implicit val realythere = implicitly[Ordering[A]]
  generalizedMergeSort(as, mergesort)
}

但无济于事。

我怀疑问题可能出在generalizedMergesort的第二个参数中。我说参数是List[A] => List[A],但我传入了List[A] => implicit Ordering[A] => List[A],但我不知道如何利用它来实现我的目标,即用mergesort来实现generalizedMergesort test.java及其本身。

2 个答案:

答案 0 :(得分:2)

简单的解决方案是从上层方法中提取隐式方法:

def mergesort[A: Ordering](as: List[A]): List[A] = {
  def mergesort0(xs: List[A]): List[A] = generalizedMergeSort(xs, mergesort0)
  mergesort0(as)
}

,第二个是用隐式包装你的函数(创建额外的对象):

def mergesort[A: Ordering](as: List[A]): List[A] = {
  val mergesort0: List[A] => List[A] = xs => mergesort(xs)
  generalizedMergeSort(as, mergesort0)
}

答案 1 :(得分:2)

您可以通过将调用mergesort的函数传递给generalizedMergeSort来解决此问题。此调用将捕获隐式Ordering

def mergesort[A: Ordering](as: List[A]): List[A] = {
  generalizedMergeSort(as, mergesort(_: List[A]))
}

mergesort(_: List[A])是类型为List[A] => List[A]的闭包函数,它使用其参数调用mergesort,并在此闭包中捕获隐式Ordering参数。