2011-10-03 6 views
6

Se si dispone di codice come 5 * 5.0, il risultato viene convertito nel tipo più preciso, Double.Come rendere il codice usando Valore [T: Numerico] più "flessibile" come le controparti "non in scatola"?

Ma questo non sembra funzionare con il codice come

case class Value[T : Numeric](value: T) { 
    type This = Value[T] 
    def +(m: This) = Value[T](implicitly[Numeric[T]].plus(value, m.value)) 
    ... 
} 

implicit def numToValue[T : Numeric](v: T) = Value[T](v) 

Esiste un modo per fare le cose come someIntValue + double lavoro, dove è someIntValueValue[Int] e double è Double?

PS: Ci scusiamo per il titolo tutt'altro che perfetto. Sono grato per i suggerimenti per una migliore formulazione ...

+1

C'è anche http://stackoverflow.com/questions/3088979/how-to-set-up-implicit-conversion-to-allow-arithmetic-between-numeric-types che potrebbe essere utile. –

risposta

5

Si può fare questo (con un sacco di busywork) attraverso la creazione di operatori impliciti:

abstract class Arith[A,B,C] { 
    def +(a: A, b: B): C 
    def -(a: A, b: B): C 
    def *(a: A, b: B): C 
    def /(a: A, b: B): C 
} 
implicit object ArithIntLong extends Arith[Int,Long,Long] { 
    def +(a: Int, b: Long) = a+b 
    def -(a: Int, b: Long) = a-b 
    def *(a: Int, b: Long) = a*b 
    def /(a: Int, b: Long) = a/b 
} 
... 
def f[A,B,C](a: A, b: B)(implicit arith: Arith[A,B,C]) = arith.*(a,b) 


scala> f(5,10L) 
res46: Long = 50 

ma devi davvero fare di più, dal momento che è necessario un equivalente numerico per A e B da solo e le operazioni asimmetriche devono essere definite in entrambi i modi. E non è davvero pratico specializzarsi dato che ci sono tre tipi coinvolti.

+0

Mhhh .... questo è davvero un problema raro che non ci sia una soluzione migliore? Un altro enorme problema con questa soluzione è che in realtà non possiamo sapere (e quindi coprire) tutti i tipi conformi a 'Numerico [T]'. – soc

+1

@soc - E 'davvero così male. Il problema è che 'Numeric' non fornisce alcun modo per dire la precisione relativa dei tre tipi. Si potrebbe rendere 'Arith' semplicemente un convertitore da' A' o 'B' a' C', e quindi avere 'C' essere' Numeric', e fare tutti i calcoli come 'C'. Ciò ridurrebbe il boilerplate, ma dovresti comunque scrivere i convertitori impliciti. –