开发者

How to fold left a list of BigDecimal? ("overloaded method + cannot be applied")

开发者 https://www.devze.com 2023-04-07 08:46 出处:网络
I want to write a short functional sum-function for a List of BigDecimal and tried with: def sum(xs: List[BigDecimal]): BigDecimal = (0 /: xs) (_ + _)

I want to write a short functional sum-function for a List of BigDecimal and tried with:

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

But I got this error message:

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

If I use Int instead, that function works. I guess this is because BigDecimal's operator overloading of +. What is a good workaround for BigDecimal?


The problem is in inital value. The solution is here and is quite simple:

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


foldLeft requires an initialization value.

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

This initialization value (named z) has to be of the same type as the type to fold over:

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

If you add an Int as initialization value the foldLeft will look like:

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


In a situation like this (where the accumulator has the same type as the items in the list) you can start the fold by adding the first and second items in the list—i.e., you don't necessarily need a starting value. Scala's reduce provides this kind of fold:

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

There are also reduceLeft and reduceRight versions if your operation isn't associative.


As others have already said, you got an error because of initial value, so correct way is to wrap it in BigDecimal. In addition, if you have number of such functions and don't want to write BigDecimal(value) everywhere, you can create implicit convert function like this:

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

and next time Scala will silently convert all your Ints (including constants) to BigDecimal. In fact, most programming languages use silent conversions from integers to decimal or even from decimals to fractions (e.g. Lisps), so it seems to be very logical move.

0

精彩评论

暂无评论...
验证码 换一张
取 消