Параметры заказа и заказа и сравнения
Дано:
case class Person(name: String)
и попытаться сделать:
scala> List(Person("Tom"), Person("Bob")).sorted
приводит к жалобе о недостающем заказе.
<console>:8: error: could not find implicit value for parameter ord: Ordering[Person]
List(Person("Tom"), Person("Bob")).sorted
Однако это:
case class Person(name: String) extends Ordered[Person] {
def compare(that: Person) = this.name compare that.name }
работает нормально, как ожидалось:
scala> List(Person("Tom"), Person("Bob")).sorted
res12: List[Person] = List(Person(Bob), Person(Tom))
хотя там не задействованы Приказы или подразумеваемые.
Вопрос №1: что здесь происходит? (Мои деньги на что-то неявное...)
Однако, учитывая сказанное выше и тот факт, что это:
scala> Person("Tom") > Person("Bob")
res15: Boolean = true
работает, и это также:
scala> List(Some(2), None, Some(1)).sorted
работает из коробки:
res13: List[Option[Int]] = List(None, Some(1), Some(2))
Я бы ожидал, что это:
scala> Some(2) > Some(1)
также будет работать, однако это не так:
<console>:6: error: value > is not a member of Some[Int]
Some(2) > Some(1)
Вопрос №2: почему бы и нет, и как я могу заставить его работать?
Ответы
Ответ 1
Относительно вашего первого вопроса: Ordered[T]
extends Comparable[T]
. Сопутствующий объект Ordering
предоставляет неявный Ordering[T]
для любого значения, которое может быть преобразовано в Comparable[T]
:
implicit def ordered[A <% Comparable[A]]: Ordering[A]
Нет никакого неявного преобразования A : Ordering => Ordered[A]
- поэтому Some(1) > Some(2)
не будет работать.
Несомненно, если это хорошая идея, чтобы определить такое преобразование, так как вы можете обернуть ваши объекты в экземпляры Ordered
, а затем снова создать Ordering
этого (и так далее...). Еще хуже: вы могли создать два экземпляра Ordered
с разными экземплярами Ordering
в области видимости, которые, конечно же, не то, что вы хотите.
Ответ 2
Если вы устанавливаете бонусы с незначительными слишком магическими для целей по умолчанию, вы можете сравнить такие варианты:
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
Импорт дает вам неявное из Ordering для класса с операциями infix, так что достаточно иметь заказ без другого импорта.
Ответ 3
Определение метода List sorted
:
def sorted [B >: A] (implicit ord: Ordering[B]): List[A]
Итак, да, неявные вещи происходят, но многие классы в стандартной библиотеке имеют неявные объекты, связанные с ними, без необходимости импортировать их в первую очередь.
Сопутствующий объект Ordering определяет кучу неявных порядков. Среди них опция OptionOrdering и IntOrdering, которая помогает объяснить возможность вызова списка sorted
.
Чтобы получить возможность использовать операторы при наличии неявного преобразования, вам необходимо импортировать этот объект, например:
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
Ответ 4
Чтобы ответить на второй вопрос, почему вы не можете сделать это: Some(2) > Some(1)
Вы можете импортировать и работать с Option[Int]
, а не 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
На практике ваши типы, вероятно, будут Option[Int]
, а не Some[Int]
, поэтому он не будет таким уродливым, и вам не понадобится явное повышение.
Ответ 5
Я предполагаю, что вы понимаете, почему сортировка не работает, когда вы не проходите в Ordering, и ни один из них не доступен в области видимости.
Что касается того, почему отсортированная функция работает, когда вы расширяете свой класс из Упорядоченного признака. Ответ заключается в том, что, когда вы расширяетесь от Упорядоченного признака, тип кода проверяет, содержит ли свойство функцию типа <, > и т.д. Поэтому нет необходимости делать неявное преобразование и, следовательно, не жалуется на недостающее неявное упорядочение.
Что касается вашего второго вопроса, Some(2) > Some(1)
не будет работать, потому что Some не расшифровывает признак Ordered, также нет какой-либо неявной функции в области видимости, которая неявно преобразует Some в то, что имеет функцию >