实际上,编写 sschaef 提出的适用于任意嵌套列表的类型类方法的版本并不难:
trait Reverser[C] {
def reverse(xs: C): C
}
implicit def rev[A](implicit ev: Reverser[A] = null) = new Reverser[List[A]] {
def reverse(xs: List[A]) =
Option(ev).map(r => xs map r.reverse).getOrElse(xs).reverse
}
def deepReverse[A](xs: A)(implicit ev: Reverser[A]): A = ev.reverse(xs)
ev
我们方法中的隐含参数rev
证明它A
本身是可逆的,如果ev
为 null 则表示不可逆。如果我们有这个可逆的证据A
,我们用它来反转我们的元素List[A]
(这就是我们map
正在做的事情),然后我们反转列表本身。如果我们没有这个证据(getOrElse
案件),我们可以把清单倒过来。
我们可以写得rev
不那么简洁(但可能更高效),如下所示:
implicit def rev[A](implicit ev: Reverser[A] = null) = if (ev == null) {
new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.reverse
}
} else {
new Reverser[List[A]] {
def reverse(xs: List[A]) = (xs map ev.reverse).reverse
}
}
要测试这两个版本中的任何一个,我们可以编写以下代码:
scala> deepReverse(List.tabulate(3)(identity))
res0: List[Int] = List(2, 1, 0)
scala> deepReverse(List.tabulate(2,3) { case (a, b) => a + b })
res1: List[List[Int]] = List(List(3, 2, 1), List(2, 1, 0))
scala> deepReverse(List.tabulate(2, 3, 4, 5, 6) {
| case (a, b, c, d, e) => a + b + c + d + e
| }).head.head.head.head
res2: List[Int] = List(15, 14, 13, 12, 11, 10)
正如预期的那样。
我应该补充一点,在这种情况下,以下是一个更常见的习语,用于正确获取隐式:
trait ReverserLow {
implicit def listReverser[A] = new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.reverse
}
}
object ReverserHigh extends ReverserLow {
implicit def nestedListReverser[A](implicit ev: Reverser[A]) =
new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.map(ev.reverse).reverse
}
}
import ReverserHigh._
如果我们只是在同一级别编写listReverser
,nestedListReverser
当我们尝试反转列表列表时会收到以下错误:
scala> deepReverse(List.tabulate(2, 3)(_ + _))
<console>:12: error: ambiguous implicit values:
both method listReverser...
and method nestedListReverser...
match expected type Reverser[List[List[Int]]]
deepReverse(List.tabulate(2, 3)(_ + _))
对两者进行优先级排序的标准方法是将较低优先级隐含在特征 ( ) 中,将另一个隐含在扩展该特征WhateverLow
的对象 ( ) 中。WhateverHigh
但是,在这样一个相当简单的情况下,在我上面的方法中使用默认参数技巧会更简洁(在我看来也更清晰)rev
。但是您更有可能在其他人的代码中看到其他版本。