Equal

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

Класс типов Equal описывает тип, который можно сравнивать на наблюдаемое равенство.

Equal должен следовать следующим законам:

Неразличимость формализует интуитивное представление о двух объектах, обладающих точно такими же свойствами. Два значения x, y: A неразличимы, если не существует такой функции f: A => Boolean, что f(x) - true, а f(y) - false.

Эти законы влекут за собой симметрию и транзитивность, которые должно быть легче проверить, поскольку они не дают универсальной количественной оценки для всех возможных предикатов в языке:

Если есть преобразование f: G => F, то из Equal[F] можно получить Equal[G].

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

trait Equal[F]:
  self =>

  def equal(a1: F, a2: F): Boolean

  def notEqual(a1: F, a2: F): Boolean = !equal(a1, a2)

  def contramap[G](f: G => F): Equal[G] =
    (a1: G, a2: G) => self.equal(f(a1), f(a2))

Реализация

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

import cats.*
import cats.implicits.*

1 === 1              // true
"Hello" =!= "World"  // true
123 === "123"        // Не скомпилируется: Type Mismatch Error
1.some =!= none[Int] // true

final case class Cat(name: String, age: Int, color: String)

given Eq[Cat] =
  Eq.instance[Cat] { (cat1, cat2) =>
    (cat1.name  === cat2.name ) &&
      (cat1.age   === cat2.age  ) &&
      (cat1.color === cat2.color)
  }

val cat1 = Cat("Garfield",   38, "orange and black")
val cat2 = Cat("Heathcliff", 32, "orange and black")
cat1 === cat2         // false

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

import scalaz.*
import Scalaz.*
List(1, 2, 3) === List(1, 2, 3) // true
List(1, 2, 3) =/= List(1, 2, 4) // true

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

import spire.math.Rational
import spire.syntax.all.*

Rational(2, 4) === Rational(3, 6) // true
Rational(2, 6) =!= Rational(3, 6) // true

Ссылки: