Equal
Формальное определение
Класс типов Equal
описывает тип, который можно сравнивать на наблюдаемое равенство.
Equal
должен следовать следующим законам:
- Рефлексивность:
x == x
для любогоx
- Неразличимость тождеств (антисимметрия): для любых
x
иy
, еслиx == y
, тоx
иy
неразличимы. - Личность неразличимых: для любых
x
иy
, еслиx
иy
неразличимы, тоx == y
Неразличимость формализует интуитивное представление о двух объектах, обладающих точно такими же свойствами.
Два значения x, y: A
неразличимы, если не существует такой функции f: A => Boolean
, что f(x)
- true
, а f(y)
- false
.
Эти законы влекут за собой симметрию и транзитивность, которые должно быть легче проверить, поскольку они не дают универсальной количественной оценки для всех возможных предикатов в языке:
- Симметричность:
x == y
тогда и только тогда, когдаy == x
- Транзитивность: если
x == y
иy == z
, тогдаx == z
Если есть преобразование 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
Ссылки: