2011-09-29 14 views
18

Dane:Kolejność i uporządkowane i porównywaniu Opcje

case class Person(name: String) 

i próbuje zrobić:

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

rezultaty w formie skargi o brak zamówieniu.

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

Jednak to:

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

działa prawidłowo zgodnie z oczekiwaniami:

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

chociaż nie ma zamawiania lub implicits zaangażowany.

Pytanie nr 1: co się tutaj dzieje? (My pieniądze na coś utajonego ...)

Jednakże, biorąc pod uwagę powyższe oraz fakt, że w ten sposób:

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

prace, a także to, że:

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

odrabia z okno:

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

Spodziewam się, że w ten sposób:

scala> Some(2) > Some(1) 

będzie również działać, jednak nie:

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

Pytanie # 2: dlaczego nie, i jak mogę zmusić go do pracy?

Odpowiedz

9

Odnośnie pierwszego pytania: Ordered[T] rozciąga Comparable[T].Ordering towarzysz obiekt zapewnia niejawny Ordering[T] dla dowolnej wartości, która może być przekształcona w Comparable[T]:

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

Nie ma niejawna konwersja A : Ordering => Ordered[A] - dlatego Some(1) > Some(2) nie będzie działać.

Jest wątpliwe, czy dobrze jest zdefiniować taką konwersję, ponieważ może zakończyć się zawijanie obiektów do instancji Ordered, a następnie ponownie utworzyć Ordering (i tak dalej ...). Co gorsza: można utworzyć dwie instancje Ordered z różnymi instancjami Ordering w zakresie, co oczywiście nie jest tym, czego potrzebujesz.

2

Definicja sorted metody tworzenia listy jest:

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

Więc tak, ukryte rzeczy dzieją się, ale wiele klas w bibliotece standardowej mają ukrytych obiektów związanych z nimi bez konieczności importowania ich w pierwszej kolejności.

Obiekt towarzyszący Ordering definiuje grupę ukrytych porządków. Wśród nich jest OptionOrdering i IntOrdering, które pomagają wyjaśnić zdolność listy do wywołania sorted.

Aby zyskać możliwość korzystania z operatorów, gdy istnieje niejawna konwersja dostępna, należy zaimportować ten obiekt, na przykład:

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

To tak naprawdę nie odpowiada na pytanie, dlaczego realizacja polecenia [T] w magiczny sposób powoduje wystąpienie Zamówienia [T]. I dlaczego musisz stworzyć metodę, aby dokonać ostatniego porównania? –

+0

Zrobiłem metodę, aby uzyskać dostęp do instancji zamawiania. Importuję zawartość tej instancji, aby uzyskać jej niejawną konwersję na 'Ops', która definiuje niektóre operatory porównania. Używając tej samej metody, w końcu zorientowałem się dokładnie, gdzie znajduje się niejawna konwersja dla 'Zamówionych'. http://www.scala-lang.org/api/current/index.html#scala.math.LowPriorityOrderingImplicits – Dylan

+0

Ale wydaje się, że sporo pracy wystarczy, aby móc porównać dwie opcje? –

23

Jeśli zainstalować implicits bonusowych nieco zbyt-magiczne-for-default-zakres, można porównać opcje tak:

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 

Import daje niejawna od zamówienia do klasy z operacje infiksów, aby wystarczyło Zamówienie bez innego importu.

+0

Lepiej ... ale wciąż dużo pracy, w mojej może nie tak skromnej opinii. :) Rozumiem, że mogą istnieć powody, dla których tak jest, ale z punktu widzenia użytkownika wydaje się logiczne, że można porównać dwie opcje bez żadnego fuzza, pod warunkiem, że można * sortować * listę bez fuzza. ... skoro musisz porównywać się w innym celu, prawda? –

+0

Możesz je sortować, ponieważ wywołujesz metodę, która przyjmuje domyślne uporządkowanie. Tutaj piszesz metodę, która przyjmuje domyślne uporządkowanie. Gdzieś, zamawiający musi wejść do obrazu, ponieważ dowolna Opcja [T] nie jest porównywalna. – extempore

0

Zakładam, że rozumiesz, dlaczego posortowane nie działa, gdy nie przekazujesz w Zamówieniu i żadne nie jest dostępne w zakresie. Informacje o tym, dlaczego posortowana funkcja działa po rozszerzeniu klasy o uporządkowaną cechę. Odpowiedź brzmi: kiedy rozszerza się z funkcji uporządkowanej, typ kodu sprawdza się, gdy cecha zawiera funkcję taką jak <,> itd. Nie ma więc potrzeby wykonywania niejawnej konwersji, a zatem nie ma narzekań na brakujące ukryte zamawianie.

Co do drugiego pytania, Some(2) > Some(1) nie będzie działać, ponieważ niektórzy nie rozciąga cecha zamówiony, ani nie wydaje się, że każdy niejawna funkcja w zakresie, że niejawnie konwertuje Niektórzy do czegoś, co ma funkcję >

2

aby odpowiedzieć na drugie pytanie, dlaczego nie może to zrobić: Some(2) > Some(1)

można z importu i pracy z Option[Int] zamiast 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 

W praktyce Twoje typy będą prawdopodobnie od Option[Int] zamiast Some[Int] więc nie będzie tak brzydki i nie trzeba będzie wyraźnej upcasting.

Powiązane problemy