2011-09-29 13 views
18

dado:Pedidos y ordenada y comparar las opciones de

case class Person(name: String) 

y tratando de hacer:

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

resultados en una queja sobre la falta de pedidos.

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

Sin embargo esto:

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

funciona bien como se esperaba:

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

aunque no hay pedidos o implícitos en cuestión.

Pregunta n. ° 1: ¿Qué está pasando aquí? (Mi dinero es algo implícito ...)

Sin embargo, teniendo en cuenta lo anterior y el hecho de que esto:

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

obras, y que también esto:

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

trabaja fuera de la caja:

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

yo esperaría que esto:

scala> Some(2) > Some(1) 

también funcionaría, sin embargo no es así:

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

Pregunta # 2: por qué no, y cómo puedo conseguir que funcione?

Respuesta

9

En cuanto a su primera pregunta: Ordered[T] extiende Comparable[T].El objeto acompañante Ordering proporciona una implícita Ordering[T] para cualquier valor que se puede convertir en un Comparable[T]:

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

no hay conversión implícita A : Ordering => Ordered[A] - es por eso Some(1) > Some(2) no va a funcionar.

Es cuestionable si es una buena idea definir dicha conversión, ya que puede terminar envolviendo sus objetos en instancias Ordered y luego crear una Ordering de eso otra vez (y así sucesivamente ...). Peor aún: podría crear dos instancias Ordered con diferentes instancias Ordering en el alcance que, por supuesto, no es lo que desea.

2

La definición del método de la Lista sorted es:

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

Así que sí, las cosas implícitas están sucediendo, pero muchas clases en la biblioteca estándar tienen objetos implícitos asociados a ellos sin tener que importarlos primero.

El objeto complementario Ordering define un conjunto de ordenamientos implícitos. Entre ellos se encuentra un OptionOrdering e IntOrdering, que ayuda a explicar la capacidad de una lista para llamar al sorted.

Para obtener la capacidad de utilizar los operadores cuando hay una conversión implícita disponibles, es necesario importar ese objeto, por ejemplo:

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

Eso realmente no responde a la pregunta de por qué implementar Ordered [T] mágicamente genera una instancia de Ordering [T]. ¿Y por qué tienes que crear un método para hacer la última comparación? –

+0

Hice el método para poder acceder a la instancia de Ordenar. Importación de los contenidos de esa instancia para que pueda obtener su conversión implícita a un 'Ops', que define algunos operadores de comparación. Usando ese mismo método, finalmente descubrí exactamente dónde está la conversión implícita para un 'Ordered '. http://www.scala-lang.org/api/current/index.html#scala.math.LowPriorityOrderingImplicits – Dylan

+0

¿Pero eso parece mucho trabajo solo para poder comparar dos opciones? –

23

Si instala los implícitos de bonificación poco-demasiado-mágico-para-default-ámbito, puede comparar opciones de este 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 

La importación le da una implícita de una Orden de la clase con el operaciones infija, para que sea suficiente tener el pedido sin otra importación.

+0

Mejor ... pero todavía mucho trabajo, en mi opinión tal vez no tan humilde. :) Entiendo que puede haber razones para que sea de esta manera, pero desde el punto de vista del usuario parece lógico que pueda comparar dos opciones sin ningún tipo de problema, dado que puede * ordenar * una lista de ellas sin ningún tipo de fuzz. ... ya que tienes que comparar en otro para ordenar, ¿verdad? –

+0

Puede ordenarlos porque llama a un método que toma un orden implícito. Aquí está escribiendo un método que toma un orden implícito. En algún lugar, un pedido debe ingresar a la imagen, porque la Opción [T] s arbitraria no es comparable. – extempore

0

Supongo que comprende por qué ordenó no funciona cuando no pasa un pedido y ninguno está disponible en el alcance. En cuanto a por qué la función ordenada funciona cuando extiende su clase desde el rasgo Ordenado. La respuesta es que cuando se extiende desde el rasgo Ordenado, el tipo de código comprueba que el rasgo contiene funciones como <,> etc. Por lo tanto, no es necesario realizar una conversión implícita y, por lo tanto, no hay quejas acerca del Ordenamiento implícito faltante.

En cuanto a su segunda pregunta, Some(2) > Some(1) no funcionará porque algunos no se extiende el rasgo Ordenado, tampoco parece haber ninguna función implícita en su alcance que implícitamente convierte una Algunos de algo que tiene la función de >

2

Para responder a su segunda pregunta, ¿por qué no puede hacer esto: Some(2) > Some(1)

Puede, con una importación y trabajando con Option[Int] en lugar de 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 

En la práctica sus tipos es probable que haya de Option[Int] en lugar de Some[Int] por lo que no será tan fea y que no necesitará el upcasting explícita.

Cuestiones relacionadas