Skip to content

Instantly share code, notes, and snippets.

@sagoez
Created April 6, 2022 22:11
Show Gist options
  • Select an option

  • Save sagoez/af6eac7489d2ceea185dac0c22dfe227 to your computer and use it in GitHub Desktop.

Select an option

Save sagoez/af6eac7489d2ceea185dac0c22dfe227 to your computer and use it in GitHub Desktop.

Revisions

  1. sagoez created this gist Apr 6, 2022.
    55 changes: 55 additions & 0 deletions contravariant.worksheet.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,55 @@
    // 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))
    }

    }