Search code examples
scalafunctorscala-cats

Apply, Applicative, Monad, etc for contravariant functors in cats?


I have the following trait...

import cats._
import cats.implicits._

trait Preference[-A] {
  self =>

  def compare(a1: A, a2: A): Int

  final def ordering[A1 <: A]: Ordering[A1] = {
    new Ordering[A1] {
      def compare(a1: A1, a2: A1): Int = {
        self.compare(a1, a2)
      }
    }
  }

}


object Preference {

  implicit val contravariant: Contravariant[Preference] = {
    new Contravariant[Preference] {
      def contramap[A, B](fa: Preference[A])(f: B => A): Preference[B] = {
        new Preference[B] {
          def compare(b1: B, b2: B): Int = {
            fa.compare(f(b1), f(b2))
          }
        }
      }
    }
  }
}

I would like to define Apply, Applicative, possibly even Monad instances for this trait but all of these type classes are extensions of Functor. Do versions of these type classes exist in Cats for contravariant functors?


Solution

  • The contravariant equivalent of Applicative in Haskell is Divisible, and cats.ContravariantMonoidal allows to define both of its methods (divide is contramap2, conquer is trivial). I am not immediately certain, though, if any Divisible has to be Monoidal in cats' sense.

    For Monad, Kmett says

    There is no contravariant Monad-like. You need C -> C, not C -> C^op. The twist denies you the ability to build nice structure.

    Also Are there contravariant monads?.