// Contravariant Functors //Formal definition says that a F[_] functor is contravariant if, instead of having the map method, it has a contramap method defined: trait Contravariant[F[_]] { def contramap[A, B](fA: F[A])(f: B => A): F[B] } // Example: type Comparison = Int val Greater = 1 val Less = -1 val Equal = 0 trait Comparator[T]{ def compare(t1: T, t2: T): Comparison } // Say we know how to compare Ints: /** if I know how to compare integers and I know how to convert ‘cucumbers’ into integer numbers, I * do know how to compare ‘cucumbers’ */ object ComparatorF extends Contravariant[Comparator] { def contramap[A, B](fa: Comparator[A])(f: B => A): Comparator[B] = new Comparator[B] { def compare(t1: B, t2: B): Comparison = fa.compare(f(t1), f(t2)) } } trait Cucumber val intC: Comparator[Int] = ??? val cucumberToInt: Cucumber => Int = ??? val cucumberC: Comparator[Cucumber] = ComparatorF.contramap(intC)(cucumberToInt) cucumberC.compare(new Cucumber{}, new Cucumber{}) // Suppose that you have a class Conversion[X, Y] representing a conversion // from a value of type X to a value of type Y. You can either combine it with // a function ? => X to preprocess the input or with a function Y=>? to postprocess the output. trait Conversion[X, Y] { self => def apply(x: X): Y def map[Z](f: Y => Z) = new Conversion[X, Z] { def apply(x: X): Z = f(self.apply(x)) } def contramap[W](f: W => X) = new Conversion[W, Y] { def apply(w: W): Y = self.apply(f(w)) } }