All You Need Is

Eq (Cats)

ScalaCats関数型プログラミング

Eq

Eq は等値性が定義されている型の集まりを表す型クラス。

cats の Eqeqv メソッドが宣言されたトレイトとして定義されている。

1
trait Eq[@sp A] extends Any with Serializable { self =>
2
3
def eqv(x: A, y: A): Boolean
4
5
def neqv(x: A, y: A): Boolean = !eqv(x, y)
6
}

neqveqv が返す真偽値とは逆の真偽値を返すメソッドとして定義されている。そのため、型の Eq インスタンスを定義したい場合は eqv メソッドだけ定義すればよい。しかし、Eq はほとんどのデータ型 (ラムダ式のような比較不可能な値を持たないデータ型) について定義できるため、定義した型ごとに Eq 型クラスのインスタンスを実装しないといけない。それはかなり面倒な作業となるため、公式ドキュメントによると二つの方法が紹介されている。

一つは、公式ドキュメントに実装が載っている Eq.fromUniversalEquals を使う方法。もう一つは、kittens という Cats を補助するライブラリを使う方法。それぞれ実際のコードは次のようになる。

1
import cats.kernel.Eq
2
3
case class Point2D(x: Int, y: Int)
4
5
given Eq[Point2D] = Eq.fromUniversalEquals

kittens を使うと derives Eq だけで済むことがわかる。 Scala 3 から Haskell の deriving 相当のことができるようになっているため、 その機能を使って Eq インスタンスが自動的に導出できる。

Eq 型クラスのインスタンスを定義すると eqveqnv のエイリアスとして ====!= が使えるようになる 1。これらの演算子 2equals メソッドと異なり、比較対象がどちらも同じ型でなければならない。 Java 由来の equals では、メソッドの引数が Any となってしまっているため、異なる型の値を比較するようなコードを書いてしまった場合にコンパイラは警告を出力するがコンパイル自体は成功してしまう。異なる型を比較したい場面というのはほとんどないため、多くの場合そのようなコードはバグでしかない。そのため、Eq 型クラスによって提供される ====!= を使ってコンパイルエラーになるように書いておくことでより安全なコードとなる。

Eq を使ったコードは EqTypeClassTest にある。

Eq のシンタックス

https://github.com/typelevel/cats/blob/v2.12.0/core/src/main/scala/cats/syntax/eq.scala

型クラスシンタックス説明
Eq=== (eqv)左辺と右辺が等値のとき true を返す。
Eq=!= (eqnv)左辺と右辺が等値ではないとき true を返す。

Footnotes

  1. 型クラスのインスタンスに対して使えるようになるメソッド、演算子は cats.syntax パッケージに定義されている。

  2. Scala における演算子はメソッドの糖衣構文 (ref: 演算子 | Scala Documentation)。


Buy Me A Coffee