Order

Формальное определение

Order предназначен для типов, которые имеют порядок. Он расширяет тип Equal. Order охватывает все стандартные функции сравнения, такие как >, <, >= и <=, а также с его помощью можно реализовать операции нахождения максимума, минимума, сортировку двух элементов и реверсивный Order.

Order должен удовлетворять следующим законам (помимо законов Equal):

Определение в виде кода на Scala

trait Equal[F]: 
  def equal(a1: F, a2: F): Boolean

enum Ordering:
  case LT
  case EQ
  case GT

trait Order[F] extends Equal[F]:
  self =>

  def order(x: F, y: F): Ordering

  def equal(x: F, y: F): Boolean = order(x, y) == Ordering.EQ

  def lessThan(x: F, y: F): Boolean = order(x, y) == Ordering.LT

  def lessThanOrEqual(x: F, y: F): Boolean = order(x, y) != Ordering.GT

  def greaterThan(x: F, y: F): Boolean = order(x, y) == Ordering.GT

  def greaterThanOrEqual(x: F, y: F): Boolean = order(x, y) != Ordering.LT

  def max(x: F, y: F): F = if greaterThanOrEqual(x, y) then x else y

  def min(x: F, y: F): F = if lessThan(x, y) then x else y

  def sort(x: F, y: F): (F, F) = if lessThanOrEqual(x, y) then (x, y) else (y, x)

  def reverseOrder: Order[F] = new Order[F]:
    def order(x: F, y: F): Ordering = self.order(y, x)
    override def equal(x: F, y: F) = self.equal(x, y)
    override def reverseOrder = self

Реализация

Реализация в Cats

import cats.*
import cats.implicits.*

1.0 compare 2.0
// val res0: Int = -1
1.0 max 2.0
// val res1: Double = 2.0

Реализация в ScalaZ

import scalaz.*
import Scalaz.*
1.0 ?|? 2.0 // Ordering.LT
1.0 lt 2.0 // true
2.0 gt 1.0 // true
1.0 lte 2.0 // true
2.0 gte 1.0 // true
1 max 2 // 2
1 min 2 // 1

Метод ?|? в ScalaZ возвращает результат сравнения Ordering: LT, GT или EQ.

Реализация в Spire

import spire.algebra.Order
import spire.math.Rational

Order.comparison(Rational(1, 2), Rational(1, 3)) // GreaterThan
Order.gt(Rational(1, 2), Rational(1, 3))         // true
Order.gteqv(Rational(1, 2), Rational(1, 3))      // true
Order.lt(Rational(1, 2), Rational(1, 3))         // false
Order.lteqv(Rational(1, 2), Rational(1, 3))      // false
Order.min(Rational(1, 2), Rational(1, 3))        // 1/3
Order.max(Rational(1, 2), Rational(1, 3))        // 1/2

Ссылки: