2011-09-29 9 views
18

Data:Ordine e opzioni ordinate e confronto

case class Person(name: String) 

e cercando di fare:

scala> List(Person("Tom"), Person("Bob")).sorted 

si traduce in una denuncia su come ordinare mancante.

<console>:8: error: could not find implicit value for parameter ord: Ordering[Person] 
    List(Person("Tom"), Person("Bob")).sorted 

Tuttavia questo:

case class Person(name: String) extends Ordered[Person] { 
    def compare(that: Person) = this.name compare that.name } 

funziona bene come ci si aspettava:

scala> List(Person("Tom"), Person("Bob")).sorted 
res12: List[Person] = List(Person(Bob), Person(Tom)) 

anche se non c'è nessun ordinamento o impliciti coinvolti.

Domanda n. 1: cosa sta succedendo qui? (Il mio denaro è qualcosa di implicito ...)

Tuttavia, dato il sopra e il fatto che questo:

scala> Person("Tom") > Person("Bob") 
res15: Boolean = true 

opere, e che anche questo:

scala> List(Some(2), None, Some(1)).sorted 

opere fuori la casella:

res13: List[Option[Int]] = List(None, Some(1), Some(2)) 

mi aspetto che questo:

scala> Some(2) > Some(1) 

sarebbe anche lavorare, ma non è così:

<console>:6: error: value > is not a member of Some[Int] 
     Some(2) > Some(1) 

Domanda # 2: perché no, e come posso farlo funzionare?

risposta

9

Per quanto riguarda la prima domanda: Ordered[T] estende Comparable[T].Il compagno oggetto Ordering fornisce un implicito Ordering[T] per qualsiasi valore che può essere convertito in un Comparable[T]:

implicit def ordered[A <% Comparable[A]]: Ordering[A] 

non c'è conversione implicita A : Ordering => Ordered[A] - è per questo che Some(1) > Some(2) non funzionerà.

È discutibile se è una buona idea definire una conversione come si potrebbe finire avvolgendo gli oggetti nelle istanze Ordered e quindi creare di nuovo uno Ordering (e così via ...). Ancora peggio: è possibile creare due istanze Ordered con diverse istanze di Ordering nell'ambito che ovviamente non è ciò che si desidera.

2

La definizione del metodo di List sorted è:

def sorted [B >: A] (implicit ord: Ordering[B]): List[A] 

Quindi sì, le cose implicite stanno accadendo, ma molte classi della libreria standard sono oggetti impliciti associati con loro senza dover importare loro per primi.

L'oggetto companion Ordering definisce una serie di ordini impliciti. Tra questi c'è un Option Order e Intor- to, che aiuta a spiegare la capacità di un elenco di chiamare sorted.

Per acquisire la capacità di utilizzare gli operatori quando v'è una conversione implicita a disposizione, è necessario importare l'oggetto, ad esempio:

def cmpSome(l:Option[Int], r:Option[Int])(implicit ord:Ordering[Option[Int]]) = { 
    import ord._ 
    l < r 
} 

scala> cmpSome(Some(0), Some(1)) 
res2: Boolean = true 
+0

Questo in realtà non risponde alla domanda perché l'implementazione di Ordered [T] comporta magicamente un'istanza di Ordering [T]. E perché devi creare un metodo per fare l'ultimo confronto? –

+0

Ho creato il metodo in modo da poter accedere all'istanza di Ordering. Importo il contenuto di quell'istanza così posso ottenere la sua conversione implicita in un 'Ops', che definisce alcuni operatori di confronto. Usando lo stesso metodo, ho finalmente capito esattamente dove si trova la conversione implicita per un 'Ordinato'. http://www.scala-lang.org/api/current/index.html#scala.math.LowPriorityOrderingImplicits – Dylan

+0

Ma questo sembra un bel po 'di lavoro solo per poter confrontare due Opzioni? –

23

Se si installano i impliciti bonus un po 'troppo magico-per-default-campo di applicazione, è possibile confrontare le opzioni in questo modo:

scala> import scala.math.Ordering.Implicits._ 
import scala.math.Ordering.Implicits._ 

scala> def cmpSome[T: Ordering](x: Option[T], y: Option[T]) = x < y 
cmpSome: [T](x: Option[T], y: Option[T])(implicit evidence$1: Ordering[T])Boolean 

L'importazione ti dà una implicita da un ordinamento per la classe con la operazioni infissi, in modo che sia sufficiente avere l'ordine senza un'altra importazione.

+0

Meglio ... ma ancora molto lavoro, nel mio parere forse non così umile. :) Capisco che potrebbero esserci motivi per cui è così, ma dal punto di vista di un utente sembrerebbe logico che tu possa confrontare due Opzioni senza alcun fuzz dato che puoi * ordinare * un elenco di esse senza alcun fuzz. ..come devi confrontare in altro per ordinare, giusto? –

+0

È possibile ordinarli perché si chiama un metodo che richiede un ordine implicito. Qui stai scrivendo un metodo che richiede un ordinamento implicito. Da qualche parte, un ordinamento deve entrare nell'immagine, perché l'Opzione arbitraria [T] s non è comparabile. – extempore

0

Suppongo tu capisca perché ordinato non funziona quando non si passa in un ordine e nessuno è disponibile nell'ambito. Per quanto riguarda il motivo per cui la funzione ordinata funziona quando estendi la tua classe dalla caratteristica Ordinata. La risposta è che quando estendi dalla caratteristica Ordinata, il tipo di codice verifica che la caratteristica contenga funzioni come <, ecc. Quindi non c'è bisogno di fare la conversione implicita e quindi non ci si lamenta per l'Ordine implicito mancante.

Per quanto riguarda la seconda domanda, Some(2) > Some(1) non funzionerà perché alcuni non si estende il tratto ordinato, né fa sembrano esserci alcuna funzione implicita di portata che converte implicitamente un Alcuni a qualcosa che ha la funzione di >

2

Per rispondere alla seconda domanda, perché non è possibile farlo: Some(2) > Some(1)

È possibile, con un'importazione e lavorando con Option[Int] anziché Some[Int].

@ import scala.math.Ordering.Implicits._ 
import scala.math.Ordering.Implicits._ 
@ Some(2) > Some(1) // doesn't work 
cmd11.sc:1: value > is not a member of Some[Int] 
val res11 = Some(2) > Some(1) 
        ^
Compilation Failed 
@ (Some(2): Option[Int]) > (Some(1): Option[Int]) // Option[Int] works fine 
res11: Boolean = true 
@ Option(2) > Option(1) 
res12: Boolean = true 
@ (None: Option[Int]) > (Some(1): Option[Int]) 
res13: Boolean = false 

In pratica i tipi di sarà probabilmente di Option[Int] piuttosto che Some[Int] in modo che non sarà così brutto e non sarà necessario l'upcasting esplicito.