関数に対するContravariantを実装する

(引き続き)Category Theory for Programmerで提示された Reader (関数)に対する ContravariantをScalaで実装してみました。
2022.07.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

引き続き今回はContravariantをやっていきます。

Readerに対するFunctor

次のような2つの型パラメータをとる型コンストラクタReaderを考えたとき、そのFunctorの実装は以下のようになります。

タプルやEitherは2つの型パラメータを入れ替えても関手性が成り立ちますが、Readerではどうでしょう?関数の向きを反転したOpを考えたときReaderに対するFunctorは定義できますがOpに対しては定義できません。

import cats.{Functor, Contravariant}

package object chap8:

  type Reader[R, A] = R => A
  type Op[R, A] = A => R

  given readerOpFunctor[R]: Functor[Op[R, *]] with
    def map[A, B](fa: Op[R, A])(f: A => B): Op[R, B] = ???

  given readerFunctor[R]: Functor[Reader[R, *]] with
    def map[A, B](fa: Reader[R, A])(f: A => B): Reader[R, B] = f compose fa

ここでOpに対するContravariant Functor の実装は以下のようになります。

  given readerOpContravariant[R]: Contravariant[Op[R, *]] with
    def contramap[A, B](fa: Op[R, A])(f: B => A): Op[R, B] = fa compose f

Law testing

ReaderおよびOpに対するEqが定義できなかったので今回はありません……

まとめ

Readerの(Covariant) FunctorとOpのContravariantの実装が対称になっているのが双対圏における射の向きと同じになっているのが印象的でした。