Подробнее об общих функциях Scala - PullRequest
21 голосов
/ 07 сентября 2011

Попытка реализовать в Scala следующую функцию Haskell (из Learn You a Haskell ...), чтобы она работала с Int, Double и т. Д.

doubleUs x y = x * 2 + y * 2 

Обратите внимание, что это похоже на Scala: Как определить «общие» параметры функции?

Вот моя попытка и ошибка.Может кто-нибудь объяснить, что происходит и предложить решение.Спасибо.

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 ]

20 голосов
/ 07 сентября 2011

В дополнение к тому, что сказал @Dylan, вы можете сделать его немного менее утомительным, импортировав в область действия содержимое Numeric, как показано ниже:

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
19 голосов
/ 07 сентября 2011

Вы используете Int литерал 2, но Scala ожидает тип Numeric A. Scala Numeric API имеет служебную функцию - def fromInt(x:Int): T.Это то, что вы хотите использовать, поэтому замените использование 2 на 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)))

Также, поскольку экземпляр Numeric определяет неявное преобразование в Ops, вы можете import numeric._скажем x * fromInt(2) + y * fromInt(2).

11 голосов
/ 07 сентября 2011

Вам нужны некоторые последствия в области:

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
}
2 голосов
/ 07 сентября 2011

Дилан, по сути, ответил, но для чего это стоит, позвольте мне предложить использовать синтаксис с привязкой к контексту вместо неявного аргумента (оба эквивалентны, и первый автоматически переписывается в последний компилятором).

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)))
}
...