21

Trying to implement, in Scala, the following Haskell function (from Learn You a Haskell...) so that it works with Int, Double, etc.

doubleUs x y = x * 2 + y * 2 

Note that this is similar to Scala: How to define "generic" function parameters?

Here's my attempt and error. Can someone explain what's happening and offer a solution. Thanks.

scala> def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A = numeric.plus(numeric.times(x,2),numeric.times(y,2)) 
<console>:34: error: type mismatch;
 found   : Int(2)
 required: A
       def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A = numeric.plus(numeric.times(x,2),numeric.times(y,2)) 
4
  • 8
    Oah... generic math looks so complicated in scala... Commented Sep 7, 2011 at 16:59
  • 2
    @FUZxxl Consequence of Java legacy and interoperability. Commented Sep 8, 2011 at 1:27
  • Coming from a C#/F#/Haskell/Mathematica background, I have to say my heart beats with bliss upon such sights of ugliness that plague languages I deliberately chose to keep away from after brief initial exposure, such as Java/Scala ^_^! There is no god in heavens that would not pity the ones that suffer such mess on a daily basis. Commented Sep 9, 2011 at 0:00
  • 2
    @Cetin: In Scala, generic math is ugly. But it can do generic math. C#, F# cannot even do generic math in a typesafe manner. Mathematica being a dynamically typed language, the comparison doesn't make sense. Commented Sep 14, 2011 at 19:26

4 Answers 4

21

In addition to what @Dylan said, you can make it look a little less tedious by importing into scope the contents of Numeric implicit as shown below:

scala> def doubleUs[N](x: N, y: N)(implicit ev: Numeric[N]) = {
     |   import ev._
     |   x * fromInt(2) + y * fromInt(2)
     | }
doubleUs: [N](x: N, y: N)(implicit ev: Numeric[N])N

scala> doubleUs(3, 4)
res9: Int = 14

scala> doubleUs(8.9, 1.2)
res10: Double = 20.2
Sign up to request clarification or add additional context in comments.

Comments

20

You are using the Int literal 2 but scala is expecting the Numeric type A. The Scala Numeric API has a utility function- def fromInt(x:Int): T. This is what you want to use, so replace your usage of 2 with numeric.fromInt(2)

def doubleUs[A](x:A,y:A)(implicit numeric: Numeric[A]): A =
  numeric.plus (numeric.times (x, numeric.fromInt (2)), numeric.times (y, numeric.fromInt (2)))

Also, since a Numeric instance defines an implicit conversion to an Ops, you can import numeric._ and then say x * fromInt(2) + y * fromInt(2).

Comments

11

You need some implicits in scope:

def doubleUs[A](x: A, y: A)(implicit num: Numeric[A]) = {
  import num._
  implicit def fromInt(i: Int) = num.fromInt(i)
  x * 2 + y * 2
}

Comments

2

Dylan essentially answered, but for what it's worth, let me suggest to use the context bound syntax instead of the implicit argument (both are equivalent, and the former is automatically rewritten into the latter by the compiler).

def doubleUs[A : Numeric](x : A, y : A) : A = {
  val num = implicitly[Numeric[A]]
  import num.{plus,times,fromInt}
  plus(times(x, fromInt(2)), times(y, fromInt(2)))
}

1 Comment

It's called a context bound, not a type annotation syntax.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.