如何折叠BigDecimal列表? (“重载方法+无法应用”)

时间:2011-09-23 22:39:51

标签: scala bigdecimal fold

我想为BigDecimal列表编写一个简短的函数和函数,并尝试使用:

def sum(xs: List[BigDecimal]): BigDecimal = (0 /: xs) (_ + _)

但我收到此错误消息:

<console>:7: error: overloaded method value + with alternatives:
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int
 cannot be applied to (BigDecimal)
       def sum(xs: List[BigDecimal]): BigDecimal = (0 /: xs) (_ + _)
                                                                ^

如果我使用Int,那么该功能可以正常工作。我想这是因为BigDecimal的运算符重载+。 BigDecimal有什么好的解决方法?

4 个答案:

答案 0 :(得分:16)

问题在于初始值。解决方案就在这里,非常简单:

 sum(xs: List[BigDecimal]): BigDecimal = (BigDecimal(0) /: xs) (_ + _)

答案 1 :(得分:2)

foldLeft需要初始化值。

def foldLeft[B](z: B)(f: (B, A) ⇒ B): B

此初始化值(名为z)必须与要折叠的类型相同:

(BigDecimal(0) /: xs) { (sum: BigDecimal, x: BigDecimal) => sum+x }
// with syntax sugar
(BigDecimal(0) /: xs) { _+_ }

如果添加Int作为初始化值,则foldLeft将如下所示:

(0 /: xs) { (sum: Int, x: BigDecimal) => sum+x } // error: not possible to add a BigDecimal to Int

答案 2 :(得分:2)

在这种情况下(累加器与列表中的项目具有相同的类型),您可以通过添加列表中的第一个和第二个项目来开始折叠 - 即,您不一定需要起始值。 Scala的reduce提供了这种折叠:

def sum(xs: List[BigDecimal]) = xs.reduce(_ + _)

如果您的操作不是关联的,还有reduceLeftreduceRight个版本。

答案 3 :(得分:0)

正如其他人已经说过的那样,由于初始值而出现错误,因此正确的方法是将其包装在BigDecimal中。另外,如果你有许多这样的函数而且不想在任何地方写BigDecimal(value),你可以创建这样的隐式转换函数:

implicit def intToBigDecimal(value: Int) = BigDecimal(value)

下次Scala会默默地将所有Int(包括常量)转换为BigDecimal。事实上,大多数编程语言使用从整数到十进制甚至从小数到分数(例如Lisps)的静默转换,因此它似乎是非常合理的移动。