2011-01-26 5 views
10

Scala tiene una serie de características que puede usar como clases de tipo, por ejemplo Ordered y Numeric en el paquete scala.math.¿Por qué el comportamiento de Numeric es diferente a lo ordenado?

puedo, por ejemplo, escribir un método genérico utilizando Ordered así:

def f[T <% Ordered[T]](a: T, b: T) = if (a < b) a else b 

que quería hacer una cosa similar con Numeric, pero esto no funciona:

def g[T <% Numeric[T]](a: T, b: T) = a * b 

¿Por qué hay una discrepancia aparente entre Ordered y Numeric?

Sé que hay otras maneras de hacer esto, el siguiente trabajo (utiliza un marco obligado):

def g[T : Numeric](a: T, b: T) = implicitly[Numeric[T]].times(a, b) 

Pero eso parece más complicado de lo que acaba de ser capaz de usar * para multiplicar dos números. ¿Por qué el rasgo Numeric no incluye métodos como *, mientras que Ordered incluye métodos como <?

Sé que hay también Ordering que se puede utilizar en la misma forma que Numeric, consulta this answer:

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b) 

Respuesta

5

Ordered son solo unos pocos métodos simples que pueden ser Int o Boolean, por lo que no es necesario ningún tipo de engaño.

Numeric, por otro lado, tiene métodos que devuelven diferentes tipos según la subclase exacta utilizada. Entonces, aunque Ordered es poco más que un rasgo de marcador, Numeric es una clase de tipo con todas las funciones.

Para recuperar sus operadores, puede usar mkNumericOps (definido en Numeric) en el operando lhs.

ACTUALIZACIÓN

Miles está del todo bien, mkNumericOps es implícita, por lo que sólo la importación de esa instancia de Numérica le va a devolver toda la magia ...

12

Los operadores simbólicos están disponibles si las importe de la implícita numérico [T]

def g[T : Numeric](a: T, b: T) = { 
    val num = implicitly[Numeric[T]] 
    import num._ 
    a * b 
} 

Esto es claramente un poco difícil de manejar si desea hacer uso de un solo operador, pero en casos no triviales la sobrecarga de la importación no es tan buena.

¿Por qué los operadores no están disponibles sin una importación explícita? Aquí se aplican las consideraciones habituales sobre la imposibilidad de hacer visibles las implícitas, tal vez más porque estos operadores son tan ampliamente utilizados.

5

Puede reducir la solución miles de usar 1 línea adicional al hacer esto:

Añadir una conversión implícita de A : Numeric a Numeric[A]#Ops

object Ops { 
    implicit def numeric[A : Numeric](a: A) = implicitly[Numeric[A]].mkNumericOps(a) 
} 

A continuación, llevar esto en todos los ámbitos del método

def g[T : Numeric](a: T, b: T) = { 
    import Ops.numeric 
    a * b 
} 

Consulte Scala ticket 3538 para obtener más información.

+0

Bonito ... ¡muy elegante! –

Cuestiones relacionadas