given the following signature for a parameterized method
def double[A <: Byte](in:List[A]): List[A] = {
//double the values of the list using foldLeft
//for ex. something like:
in.foldLeft(List[A]())((r,c) => (2*c) :: r).reverse
//but it doesn't work! so..
}
i was trying to get the following before tackling parameterized typed foldLeft
def plainDouble[Int](in:List[Int]): List[Int] = {
in.foldLeft(List[Int]())((r:List[Int], c:Int) => {
var k = 2*c
println("r is ["+r+"], c is ["+c+"]")
//want to prepend to list r
// k :: r
r
})
}
however, this results in the following error:
$scala fold_ex.scala
error: overloaded method value * with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: scala.Int)scala.Int <and>
(x: Char)scala.Int <and>
(x: Short)scala.Int <and>
(x: Byte)scala.Int
cannot be applied to (Int(in method plainDouble))
val k = 2*c
^
one error found
if i changed the signature of the def to the following:
def plainDouble(in:List[Int]): List[Int] = { ...}
works and the output for :
val in = List(1,2,3,4,5)
println("in "+ in + " plainDouble ["+plainDouble(in)+"]")
is
in List(1, 2, 3, 4, 5) plainDouble [List(2, 4, 6, 8, 10)]
apologies if i am missing something very obvious.
@DNA is correct in that plainDouble[Int]
declares a type parameter named Int
, that has nothing to do with the actual type. So your attempt to make it non-generic is actually still generic, but in a way that is not quickly apparent.
But what about the original problem?
scala> def double[A <: Byte](in: List[A]): List[A] = in.foldLeft(List.empty[A])((r,c) => (2*c) :: r)
<console>:15: error: type mismatch;
found : x$1.type (with underlying type Int)
required: A
def double[A <: Byte](in: List[A]): List[A] = in.foldLeft(List.empty[A])((r,c) => (2*c) :: r).reverse
^
The problem here is that 2 * c
is an Int
, and not an A
. The *(byte: Byte)
method on Int
returns another Int
. Hence the message (with underlying type Int)
. Notice that if you cast to A
, it compiles:
def double[A <: Byte](in: List[A]): List[A] =
in.foldLeft(List.empty[A])((r,c) => (2*c).toByte.asInstanceOf[A] :: r).reverse
Notice how I also had to call toByte
before casting to A
. This isn't exactly a shining example of generics at work, but the point is that incompatible return types are causing the error.
Also notice how it doesn't occur if you remove 2 *
:
def double[A <: Byte](in: List[A]): List[A] =
in.foldLeft(List.empty[A])((r,c) => c :: r).reverse
Edit:
You might consider using the Numeric
trait for generics like this.
import scala.math.Numeric.Implicits._
def double[A: Numeric](in: List[A])(implicit i2a: Int => A): List[A] =
in.map(_ * 2)
This relies on an implicit Numeric[A]
being available for your numeric type (which there are in the scala.math.Numeric
object, for pretty much any numeric type you will want). It also relies on an implicit conversion being available from Int
to A
, so that we can write a * 2
. We can drop this constraint by using +
instead:
def double[A: Numeric](in: List[A]): List[A] = in.map(a => a + a)