2011-03-01 60 views
1

任何人都可以帮助我理解这段代码吗?我对斯卡拉一无所知,也没有听说过。需要帮助Scala

def maxSubseq(l: List[Int]) = l.scanRight(Nil : List[Int]) { 
    case (el, acc) if acc.sum + el < 0 => Nil 
    case (el, acc) => el :: acc 
} max Ordering.by((_: List[Int]).sum) 

def biggestMaxSubseq(l: List[Int]) = l.scanRight(Nil : List[Int]) { 
    case (el, acc) if acc.sum + el < 0 => Nil 
    case (el, acc) => el :: acc 
} max Ordering.by((ss: List[Int]) => (ss.sum, ss.length)) 

def biggestMaxSubseq[N](l: List[N])(implicit n: Numeric[N]) = { 
    import n._ 
    l.scanRight(Nil : List[N]) { 
     case (el, acc) if acc.sum + el < zero => Nil 
     case (el, acc) => el :: acc 
    } max Ordering.by((ss: List[N]) => (ss.sum, ss.length)) 
} 

def linearBiggestMaxSubseq[N](l: List[N])(implicit n: Numeric[N]) = { 
    import n._ 
    l.scanRight((zero, Nil : List[N])) { 
     case (el, (acc, _)) if acc + el < zero => (zero, Nil) 
     case (el, (acc, ss)) => (acc + el, el :: ss) 
    } max Ordering.by((t: (N, List[N])) => (t._1, t._2.length)) _2 
} 

该代码是否可以在Java中实现?

+4

购买一本书从[斯卡拉开始 - 大卫波拉克](http://www.amazon.com/Beginning-Scala-David-Pollak/dp/1430219890) – Nishant

+2

是的,我认为它可以用Java实现,但是这很愚蠢。一个scala编译器可以让你生成可以直接从java使用的类文件。 – Benson

+2

我的大脑受伤了。忘了在Java中实现这个令人费解的混乱,我认为它需要在Scala中更加干净地实现! –

回答

7

当然,它可以用Java实现。不过,这需要更多的努力。我们来看看这里的一些观点。

def linearBiggestMaxSubseq[N](l: List[N])(implicit n: Numeric[N]) = { 

这声明其接收的N一个List的方法,以及隐式参数Numeric[N]。隐式参数通常由编译器自己通过查找特定位置来匹配所需参数的声明来获得 - 几乎就像依赖注入一样。

在这种情况下,Numeric[N]是一个提供基本数学运算的类,对于该类,标准库中提供了所有数字类型的实例。该方法从Numeric使用的唯一的东西是pluszero

Java没有隐含含义,所以等价的Java API使用起来会比较麻烦,需要传递一个额外的参数。

此外,我不记得在Java中任何等效于Numericjava.lang.Number不提供在BigIntBigDecimal中找到的方法。您必须编写自己的等效Numeric,然后编写实例以涵盖所有数字类型,然后客户端代码将不得不显式传递该实例。如果Java有其他选择去做所有这些努力,我很乐意听到它。

import n._ 

这一切确实是让代码做acc + el而不是n.plus(acc, el),并zero而不是n.zero。它如何做,超出了这个问题的范围。

l.scanRight((zero, Nil : List[N])) { 

在Java中没有scanRight等效。你必须把它变成一个while循环,但这并不是特别困难。一个scanRight将从右到左遍历列表(尽管我没有看到任何原因,为什么代码是正确的,而不是从左到右更容易和高效)。当它遍历列表(l)时,它将调用传递两个参数的函数:当前元素和“累加器”。这里的累加器是一个Pair,它是一个浅对象,包含两个元素的getter和setter。第一次,这一对初始化为zeroNil(一个空列表)。

scanRight调用的方法应该返回与累加器类型相同的东西 - 因此,通过了Pair[N, List[N]],它应该返回一个新的Pair[N, List[N]]

最后,scanRight将创建一个包含调用方法结果的集合。在该代码中,这将有

case (el, (acc, _)) if acc + el < zero => (zero, Nil) 
    case (el, (acc, ss)) => (acc + el, el :: ss) 

大量物质匹配到由一系列if/else语句来替换。详细,但不是特别麻烦。

在这种特殊情况下,(el, (acc, _))(ec, (acc, ss))只是传递的参数。他们可能包含测试,但在这里,他们不。唯一的测试是acc + el < zero。如果是,则返回(zero, Nil),否则返回(acc + el, el :: ss)。正如我刚才所说,Nil是一个空的列表。这里,el :: ss返回一个新的列表,其中el列在ss的前面。

} max Ordering.by((t: (N, List[N])) => (t._1, t._2.length)) _2 

至少Java的数字类通常实现Comparable,即使他们没有实现提供数字操作的接口。有许多Ordering.by实例,其中每个实例都需要Comparator等效或某种其他临时解决方案。

无论如何,这将返回的最大元素(max),使用Ordering(相当于Comparator),其首先考虑对的第一元素的值,并且所述第二元件的长度对(这是一个列表)。

最后,_2将丢弃该对的第一个元素并返回第二个元素。

这是所有方法中最复杂的。以前的更简单,代价是不那么通用和高效。

因此,Java版本将会更加冗长,当然,除了Numeric问题之外,应该是非常直接的编写。再次,Numeric问题非常关键。