2015-05-20 3 views
2

У меня возникли проблемы со следующим полиморфного определения функции:Treat Тип параметра в числовом Использование Implicits

scala> def foo[A](x : A, y : A)(implicit o : A => Numeric[A]) : A = x + y 
<console>:7: error: type mismatch; 
found : A 
required: String 
     def foo[A](x : A, y : A)(implicit o : A => Numeric[A]) : A = x + y 

Я хотел бы указать, что параметр типа A может быть использован в качестве Numeric, но это не работает , Что я делаю не так?

ответ

4

A Numeric[A], как правило, один экземпляр, который дает доступ к арифметическим операциям по типу A. Он будет содержит def plus(x: A, y: A): A, а не def add(x: A): A, которая будет иметь некоторый this типа А.

Это сродни в Java Comparator (или в Scala Ordering), который имеет Compare(T o1, T o2), а не Java Comparable (Скала Ordered), который имеет CompareTo(T other). Такие типы с неявно доступными реализациями singleton обычно называются степенными классами после тесно связанной функции на языке Haskell.

Поэтому вы не хотите конвертировать A в Numeric[A], вы просто хотите получить Numeric[A]. Ваша подпись должна быть

def foo[A](x: A, y: A)(implicit numeric: Numeric[A]) 

Существует ярлык для того, что

def foo[A: Numeric](x: A, y: A) 

В методе foo, вы можете сделать numeric.plus(x,y), но если вы import scala.math.Numeric._, вы получаете некоторые магии и многое другое удобный x + y.


Что касается вопроса в комментарии: еще не было изменение языка программирования, так как в Скале (который находится на против 2.8)?

Синтаксис [A: Numeric], названный context bound, был введен на позднем языке, я не уверен на 100%, но я считаю, что он не был доступен в 2.8. Но это всего лишь ярлык для аргумента implicit Numeric[A], который был возможен в 2,8 (Numeric был доступен, только что введенный в 2.8) и должен был использоваться, как показано выше в то время. Кроме того, не было языкового изменения.

Однако в ранние времена Скале, это было более распространено использование «представления», то есть неявные преобразования, а не классы типов, то есть использовать такие типы, как Comparable/Ordered, а не Comparator/Ordering/Numeric.

Для таких типов вы обычно используете верхнюю границу A <: Ordered[A]. Однако это может быть чересчур слишком ограничительным, поскольку оно будет работать только в том случае, если разработчику было предвидение для реализации Ordered. Вы можете обойти это, но требуя, чтобы A мог быть преобразован в Упорядоченный [A], поэтому implicit A => Ordered[A].

Раньше был ярлык для этого, [A <% Ordered[A]], называемый вид связан. Тем не менее, он устарел, и в то время как представления все еще возможны (implicit A => Ordered[A]), классные категории очень предпочтительны. Есть много причин для этого, например .:

  • , имеющие функции преобразования в неявной области будет действовать как неявные слепки и довольно опасны
  • классов типов являются более мощными. Например, вы можете иметь экземпляр Numeric[A], даже если у вас нет экземпляров A, и поэтому получите zero типа A. если вы вызываете sum в список, и список пуст, Numeric по-прежнему доступен, и вы можете получить zero. если Numeric было что-то реализовано A, даже если оно было сделано zero, у вас не было бы экземпляра, чтобы позвонить ему. Еще один пример: typeclass может использоваться как завод, опять же, когда у вас нет экземпляра построенного типа (пока), как показано в this answer.

Цитирую Одерски (discussing deprecation):

контекста оценки, по существу, замена зрения границ. Это Что мы должны были сделать с самого начала, но мы не знали лучше тогда

+0

Спасибо. Have Typesafe изменил синтаксис для implicits, когда я передрабил фрагмент кода из книги Programming in Scala, в которой была определена функция, как я сделал в своем сообщении. –

+0

ответил в ответе выше –

2

два изменений, которые необходимы в том, что, первомimplicit не должен быть функцией от A к Numeric[A], а просто Numeric[A] и второго вам нужно импортировать Numeric.Implicits, чтобы получить неявные Ops, что позволит +.

import scala.math.Numeric.Implicits._ 

def foo[A](x : A, y : A)(implicit num: Numeric[A]) : A = x + y 

Без импорта вы должны написать:

def foo[A](x : A, y : A)(implicit num: Numeric[A]) : A = num.plus(x,y) 
Смежные вопросы