2

I've tried this line of code

def **[A <% Numeric[A]](l:List[A],m:List[A])=l.zip(m).map({t=>t._1*t._2})

However on compilation, I get this error

error: value * is not a member of type parameter A
def **[A <% Numeric[A]](l:List[A],m:List[A])=l.zip(m).map({t=>t._1*t._2})

When I look at the source for the Numeric trait, I see a * op defined.

What am I doing wrong?

user44242
  • 1,168
  • 7
  • 20

2 Answers2

7

The instance of Numeric is not a number itself, but it is an object that offers operations to do the arithmetic. For example, an object num of type Numeric[Int] can add two integers like this: num.plus(3, 5) The result of this operation is the integer 7.

For integers, this is very trivial. However, for all basic numerical types, there is one implicit instance of Numeric available. And if you define your own numeric types, you can provide one.

Therefore, you should leave the bounds for A open and add an implicit parameter of type Numeric[A], with which you do the calculations. Like this:

def **[A](l:List[A],m:List[A])(implicit num:Numeric[A])=l.zip(m).map({t=>num.times(t._1, t._2)})

Of course, num.times(a,b) looks less elegant than a*b. In most of the cases, one can live with that. However, you can wrap the value a in an object of type Ops that supports operators, like this:

// given are: num:Numeric[A], a:A and b:A
val a_ops = num.mkNumericOps(a)
val product = a_ops * b

Since the method mkNumericOps is declared implicit, you can also import it and use it implicitly:

// given are: num:Numeric[A], a:A and b:A
import num._
val product = a * b
Madoc
  • 5,841
  • 4
  • 25
  • 38
  • 1
    Where would I put the import num._ statement in the context of my ** function? – user44242 Dec 14 '10 at 09:00
  • 1
    You would need to open a block after the equals sign. I didn't test this, but I assume it would have to look like this: `def **[A](l:List[A],m:List[A])(implicit num:Numeric[A])={ import num._ ; l.zip(m).map({t=>t._1 * t._2}) }` -- I would try to go without it though; I'm unsure if the creation of the implicit wrapper Ops object affects performance, or if it will be optimized by the compiler. – Madoc Dec 14 '10 at 09:04
  • I expect it should be optimized if escape analysis is enabled, but no guarantees. – Alexey Romanov Dec 14 '10 at 18:39
2

You can also solve this with a context bound. Using the context method from this answer, you can write:

def **[A : Numeric](l:List[A],m:List[A]) =
   l zip m map { t => context[A]().times(t._1, t._2) }

or

def **[A : Numeric](l:List[A],m:List[A]) = {
   val num = context[A]()
   import num._
   l zip m map { t => t._1 * t._2 }
}
Community
  • 1
  • 1
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108