Skip to content

Instantly share code, notes, and snippets.

@cscalfani
Last active January 4, 2021 20:47
Show Gist options
  • Select an option

  • Save cscalfani/f5f601e49b8f8eb77997e178ef9a7965 to your computer and use it in GitHub Desktop.

Select an option

Save cscalfani/f5f601e49b8f8eb77997e178ef9a7965 to your computer and use it in GitHub Desktop.

Revisions

  1. cscalfani revised this gist Nov 28, 2017. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,8 @@ This article contains more than enough examples to hopefully understand Covarian

    Note that all type annotations use `Int` as the concrete type but any concrete type would be equivalent as would any mix of concrete types.

    It assumes a general understanding of `Functor` and a basic understanding of Haskell type classes and data types.

    ## Mapping from `a` to `b`(#1)

    We would like to map `a`'s to `b`'s using a mapping function whose signature is `a -> b`.
  2. cscalfani revised this gist Nov 27, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -403,7 +403,7 @@ This mapping can be written like:
    ```haskell
    Int -> (Int -> a)
    ```
    which are not necessary since arrows, `->`, associate to the right. But it's important to draw them like this for just long enough for us to recognize that we are dealing with the polar opposite signatures than we've been dealing with so far which were asociated to the left.
    which are not necessary since arrows, `->`, associate to the right. But it's important to draw them like this for just long enough for us to recognize that we are dealing with the polar opposite signatures than we've been dealing with so far which were associated to the left.

    But it is clear that these forms are going to be easier to deal with.

  3. cscalfani revised this gist Nov 27, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -285,7 +285,7 @@ Turns out that that approach worked great.

    ## Mapping from `(((a -> Int) -> Int) -> Int) -> Int` to `(((b -> Int) -> Int) -> Int) -> Int` (#9)

    At this point, it would be nice at this point if we could just follow some pattern and not have to figure this out type by type.
    It would be nice, at this point, if we could just follow some pattern and not have to figure this out type by type.

    Although, it's not a simple pattern, there are some rules to this pattern that arise:

  4. cscalfani revised this gist Nov 27, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -255,7 +255,7 @@ Looking at the final function in detail:
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ((a -> Int) -> (b -> Int) -> Int) ((a -> Int) . (b -> a)))
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ((a -> Int) -> (b -> Int) -> Int) ( b -> Int ))
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ((a -> Int) -> Int )
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ( (a -> Int) -> Int )
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ( (a -> Int) -> Int )
    ((b -> Int) -> Int) -> Int
    ```
    Looks like we can keep `Generalization #2` for now. Maybe with enough experience we can further generalize it.
  5. cscalfani revised this gist Nov 27, 2017. 1 changed file with 16 additions and 1 deletion.
    17 changes: 16 additions & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -231,18 +231,33 @@ So we must create yet another function, let's call it `hh`, which has the type t
    So far, we have:

    ```haskell
    h :: (a -> Int)
    f :: (b -> a)

    h . f :: b -> Int
    hh :: (b -> Int) -> Int

    \h -> hh(h . f) :: (a -> Int) -> Int
    ```

    which is perfect for applying to our original function `g`, `((a -> Int) -> Int) -> Int` giving us our final solution:
    `\h -> hh(h . f)` is perfect for applying to our original function `g`, i.e. `((a -> Int) -> Int) -> Int` giving us our final solution:

    ```haskell
    newtype F7 a = F7 (((a -> Int) -> Int) -> Int)

    instance Contravariant F7 where
    contramap f (F7 g) = F7 (\hh -> g (\h -> hh(h . f)))
    ```
    Looking at the final function in detail:

    ```haskell
    \hh -> g (\h -> hh (h . f ))
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ((a -> Int) -> (b -> Int) -> Int) ((a -> Int) . (b -> a)))
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ((a -> Int) -> (b -> Int) -> Int) ( b -> Int ))
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ((a -> Int) -> Int )
    ((b -> Int) -> Int) -> (((a -> Int) -> Int) -> Int) ( (a -> Int) -> Int )
    ((b -> Int) -> Int) -> Int
    ```
    Looks like we can keep `Generalization #2` for now. Maybe with enough experience we can further generalize it.

    ## Mapping from `((Int -> a) -> Int) -> Int` to `((Int -> b) -> Int) -> Int` (#8)
  6. cscalfani revised this gist Nov 27, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -179,7 +179,7 @@ In fact, the rules seemed to change to the polar opposite every time we enter a

    So let's assume that it flips as we enter parenthesis and see if this flipping continues by mapping with yet another parenthetical group to get a better understanding of when we use a `Covariant` as opposed to a `Contravariant`.

    ##A mapping strategy emerges
    ## A mapping strategy emerges

    In #2 and #3, the function composed with `f`, our mapping function, has converted either an `a -> Int` to `b -> Int` or an `Int -> a` to `Int -> b`. In those cases that was sufficient since these were simple type mappings.

  7. cscalfani revised this gist Nov 27, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -124,7 +124,7 @@ instance Functor F5 where
    fmap f (F5 g) = F5 (\h -> g (h . f))
    ```

    Lookin at `h` in detail and replacing types and reducing gives us:
    Looking at `h` in detail and replacing types and reducing gives us:

    ```
    \h -> g ( h . f )
  8. cscalfani revised this gist Nov 21, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -50,7 +50,7 @@ instance Functor F3 where

    We may think that `g . f` would work by first converting the input using `f` and then calling the original function `g`.

    Problem is that `f` would need to be `b -> a` which is NOT how functor was defined in #1.
    Problem is that `f` would need to be `b -> a` which is NOT how `Functor` was defined in #1.

    What we need a different *Functor-like* class that will work with mapping functions with reversed signatures.

  9. cscalfani revised this gist Nov 16, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -441,7 +441,7 @@ callMap1of2 :: (b -> a) -> (a -> c -> d) -> b -> c -> d
    callMap1of2 f g x = g (f x)
    ```

    `callMap2of2` will call our original function, `g`, and map the 2nd parameter of a 2 parameters function call.
    `callMap2of2` will call our original function, `g`, after mapping the 2nd parameter of a 2 parameter function call.

    `callMap1of2` does the same except it maps the 1st parameter and we'll use it later.

  10. cscalfani revised this gist Nov 16, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -396,7 +396,7 @@ This particular mapping is easy. We simply call the function and then map the re

    Since we are converting a `return value` of type `a` to be of type `b`, we need a mapping function from `a -> b` which means we need to use `Functor`.

    But first we need a few helper functions written with it's parameters backwards from what would be traditional to help us keep track of our mapping functions `f`:
    But first we need a few helper functions with it's parameter names written backwards from what would be traditional to help us keep track of our mapping functions `f`:

    ```haskell
    compose2 :: (a -> b -> c) -> (c -> d) -> a -> b -> d
  11. cscalfani revised this gist Nov 16, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -388,7 +388,7 @@ This mapping can be written like:
    ```haskell
    Int -> (Int -> a)
    ```
    which are not necessary since arrows, `->`, associate to the right. But it's important to draw them like this for just long enough for use to recognize that we are dealing with the polar opposite signatures than we've been dealing with so far which were asociated to the left.
    which are not necessary since arrows, `->`, associate to the right. But it's important to draw them like this for just long enough for us to recognize that we are dealing with the polar opposite signatures than we've been dealing with so far which were asociated to the left.

    But it is clear that these forms are going to be easier to deal with.

  12. cscalfani revised this gist Nov 16, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -301,7 +301,7 @@ The two cases only differ by the order of composition.

    But as additional `-> Int`'s got added, e.g. moving from #4 to #6, `g` gets *pulled out* and replaced with an anonymous function, we progressively called `h` then `hh`, etc.

    This new construct get applied to `g`, our original function as the final step.
    This new construct gets applied to `g`, our original function as the final step.

    Then the whole thing is wrapped by this anonymous function.

  13. cscalfani revised this gist Nov 16, 2017. 1 changed file with 20 additions and 20 deletions.
    40 changes: 20 additions & 20 deletions coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,10 @@
    #Covariant and Contravariant Functors
    # Covariant and Contravariant Functors

    This article contains more than enough examples to hopefully understand Covariant and Contravariant Functors and how to create them for many situtations.

    Note that all type annotations use `Int` as the concrete type but any concrete type would be equivalent as would any mix of concrete types.

    ##Mapping from `a` to `b`(#1)
    ## Mapping from `a` to `b`(#1)

    We would like to map `a`'s to `b`'s using a mapping function whose signature is `a -> b`.

    @@ -24,7 +24,7 @@ instance Functor F1 where

    `g` has type `a` and `f g` has type `b`.

    ##Mapping from `Int -> a` to `Int -> b` (#2)
    ## Mapping from `Int -> a` to `Int -> b` (#2)

    Now we map the result of a function call.

    @@ -39,7 +39,7 @@ Essentially, we call our original function `g` and then convert the return from

    Type substitution on `f . g` yields `a -> b . Int -> a` which reduces to `Int -> b`.

    ##Mapping from `a -> Int` to `b -> Int` (#3)
    ## Mapping from `a -> Int` to `b -> Int` (#3)

    ```haskell
    newtype F3 a = F3 (a -> Int)
    @@ -74,7 +74,7 @@ Compare `F2`'s `instance` (`Functor`) with `F3`'s `instance` (`Contravariant`).

    The only difference is the order the composition of `f` and `g` and the `class` changed from `Functor` to `Contravariant`.

    ##Generalization #1
    ## Generalization #1

    Note that mapping from `Int -> a` to `Int -> b` with `a -> b` (#2) used `Functor`, but mapping from `a -> Int` to `b -> Int` with `a -> b` (#3) was not possible and required a mapping function of `b -> a` and `Contravariant`.

    @@ -86,7 +86,7 @@ And if a function has 2 parameters and the polymorphic parameter is on the left

    This generalization is far from complete since it is restricted to functions of 2 parameters. Let's continue to look at more complex examples to see if we can get a better understanding of when to use `Functor` and when to use `Contravariant`.

    ##Mapping from `(Int -> Int) -> a` to `(Int -> Int) -> b` (#4)
    ## Mapping from `(Int -> Int) -> a` to `(Int -> Int) -> b` (#4)

    If `Generalization #1` is right, then we should use `Functor` since the polymorphic parameter is in the rightmost position.

    @@ -101,7 +101,7 @@ Here `g` takes `(Int -> Int)` and returns an `a` into f which takes an `a` and r

    And so far, `Generalization #1` is holding.

    ##Mapping from `(a -> Int) -> Int` to `(b -> Int) -> Int` (#5)
    ## Mapping from `(a -> Int) -> Int` to `(b -> Int) -> Int` (#5)

    ```haskell
    newtype F5 a = F5 ((a -> Int) -> Int)
    @@ -135,7 +135,7 @@ Lookin at `h` in detail and replacing types and reducing gives us:

    This is exactly what we were aiming for, i.e. `(b -> Int) -> Int`.

    ##Mapping from `(Int -> a) -> Int` to `(Int -> b) -> Int` (#6)
    ## Mapping from `(Int -> a) -> Int` to `(Int -> b) -> Int` (#6)

    ```haskell
    newtype F6 a = F6 ((Int -> a) -> Int)
    @@ -163,7 +163,7 @@ Lookin at `h` in detail and replacing types and reducing gives us:

    Once again, this is exactly what we were aiming for, i.e. `(Int -> b) -> Int`.

    ##Generalization #2
    ## Generalization #2

    Now that we've done some more complex mappings, it's time to revisit `Generalization #1`, which we knew was incomplete.

    @@ -191,7 +191,7 @@ Then we applied that to the original function to get our final type mapping.

    As we move to more complex mappings, we can expect to use the strategy from #5 and #6 to get us part of the way there.

    ##Mapping from `((a -> Int) -> Int) -> Int` to `((b -> Int) -> Int) -> Int` (#7)
    ## Mapping from `((a -> Int) -> Int) -> Int` to `((b -> Int) -> Int) -> Int` (#7)

    ```haskell
    newtype F7 a = F7 (((a -> Int) -> Int) -> Int)
    @@ -245,7 +245,7 @@ instance Contravariant F7 where

    Looks like we can keep `Generalization #2` for now. Maybe with enough experience we can further generalize it.

    ##Mapping from `((Int -> a) -> Int) -> Int` to `((Int -> b) -> Int) -> Int` (#8)
    ## Mapping from `((Int -> a) -> Int) -> Int` to `((Int -> b) -> Int) -> Int` (#8)

    Looking at the pattern of solutions for #5 and #6, we can see that there are 2 difference:

    @@ -268,7 +268,7 @@ instance Functor F8 where

    Turns out that that approach worked great.

    ##Mapping from `(((a -> Int) -> Int) -> Int) -> Int` to `(((b -> Int) -> Int) -> Int) -> Int` (#9)
    ## Mapping from `(((a -> Int) -> Int) -> Int) -> Int` to `(((b -> Int) -> Int) -> Int) -> Int` (#9)

    At this point, it would be nice at this point if we could just follow some pattern and not have to figure this out type by type.

    @@ -358,7 +358,7 @@ All of these `h`'s are making my eyes glaze over. Let's simplify:
    (\h6 -> g (\h5 -> h6(\h4 -> h5(\h3 -> h4(\h2 -> h3(\h -> h2(h . f)))))))
    ```

    ##Mapping from `(((Int -> a) -> Int) -> Int) -> Int` to `(((Int -> b) -> Int) -> Int) -> Int` (#10)
    ## Mapping from `(((Int -> a) -> Int) -> Int) -> Int` to `(((Int -> b) -> Int) -> Int) -> Int` (#10)

    Going from #9 to #10 is far easier than going from #7 to #9.

    @@ -373,15 +373,15 @@ instance Contravariant F10 where
    contramap f (F10 g) = F10 (\hhh -> g (\hh -> hhh(\h -> hh(f . h))))
    ```

    ##Now what?
    ## Now what?

    No sense in continuing since a pattern has arisen that can be used to generate more and more complex versions.

    Besides, we've long since surpassed any reasonable likelihood that we'll see such signatures in the wild.

    But what about other signature forms?

    ##Mapping from `Int -> Int -> a` to `Int -> Int -> b` (#11)
    ## Mapping from `Int -> Int -> a` to `Int -> Int -> b` (#11)

    This mapping can be written like:

    @@ -425,7 +425,7 @@ instance Functor F11 where
    In `compose2`, our mapping function, `f`, is executed last to convert the return of `g` from `a` to `b`.


    ##Mapping from `Int -> a -> Int` to `Int -> b -> Int` (#12)
    ## Mapping from `Int -> a -> Int` to `Int -> b -> Int` (#12)

    Here, we are mapping a `parameter` of type `a` instead of a `return value`, which means we'll need to map the `parameter` from `b` to `a` **before** we call our original function, `g`.

    @@ -454,7 +454,7 @@ instance Contravariant F12 where
    contramap f (F12 g) = F12 (callMap2of2 f g)
    ```

    ##Mapping from `a -> Int -> Int` to `b -> Int -> Int` (#13)
    ## Mapping from `a -> Int -> Int` to `b -> Int -> Int` (#13)

    Once again we are mapping a `parameter` except the only difference between this mapping and #12 is that `parameter` is the 1st.

    @@ -467,7 +467,7 @@ instance Contravariant F13 where
    contramap f (F13 g) = F13 (callMap1of2 f g)
    ```

    ##Mapping from `Int -> ... -> a` to `Int -> ... -> b` (#14)
    ## Mapping from `Int -> ... -> a` to `Int -> ... -> b` (#14)

    This is a general case of #11 and will look something like:

    @@ -481,7 +481,7 @@ instance Functor F14 where

    where `composeN` is the compose function where `N` is the count of concrete parameters.

    ##Mapping from `a -> ... -> Int` to `b -> ... -> Int` (#15)
    ## Mapping from `a -> ... -> Int` to `b -> ... -> Int` (#15)

    This is the general case of #12 and #13 and will look something like:

    @@ -495,6 +495,6 @@ instance Contravariant F15 where

    where `callMapNofM` is the parametric mapping function that maps the `N`th parameter of a function of `M` parameters.

    ##Conclusion
    ## Conclusion

    Hopefully, working through all of these examples will help to inform how and when to use `Functor` or `Contravariant`.
  14. cscalfani revised this gist Nov 16, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Covariant and Contravariant Functors
    #Covariant and Contravariant Functors

    This article contains more than enough examples to hopefully understand Covariant and Contravariant Functors and how to create them for many situtations.

    @@ -74,7 +74,7 @@ Compare `F2`'s `instance` (`Functor`) with `F3`'s `instance` (`Contravariant`).

    The only difference is the order the composition of `f` and `g` and the `class` changed from `Functor` to `Contravariant`.

    ## Generalization #1
    ##Generalization #1

    Note that mapping from `Int -> a` to `Int -> b` with `a -> b` (#2) used `Functor`, but mapping from `a -> Int` to `b -> Int` with `a -> b` (#3) was not possible and required a mapping function of `b -> a` and `Contravariant`.

  15. cscalfani revised this gist Nov 16, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -163,7 +163,7 @@ Lookin at `h` in detail and replacing types and reducing gives us:

    Once again, this is exactly what we were aiming for, i.e. `(Int -> b) -> Int`.

    ## Generalization #2
    ##Generalization #2

    Now that we've done some more complex mappings, it's time to revisit `Generalization #1`, which we knew was incomplete.

  16. cscalfani created this gist Nov 16, 2017.
    500 changes: 500 additions & 0 deletions coContraFunctors.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,500 @@
    # Covariant and Contravariant Functors

    This article contains more than enough examples to hopefully understand Covariant and Contravariant Functors and how to create them for many situtations.

    Note that all type annotations use `Int` as the concrete type but any concrete type would be equivalent as would any mix of concrete types.

    ##Mapping from `a` to `b`(#1)

    We would like to map `a`'s to `b`'s using a mapping function whose signature is `a -> b`.

    The following is the canonical `Functor` definition and an implemenation for `F1`:

    ```haskell
    class Functor f where
    fmap :: (a -> b) -> f a -> f b

    newtype F1 a = F1 a

    instance Functor F1 where
    fmap f (F1 g) = F1 (f g)
    ```

    `f` is our mapping function that takes an `a` and returns a `b`.

    `g` has type `a` and `f g` has type `b`.

    ##Mapping from `Int -> a` to `Int -> b` (#2)

    Now we map the result of a function call.

    ```haskell
    newtype F2 a = F2 (Int -> a)

    instance Functor F2 where
    fmap f (F2 g) = F2 (f . g)
    ```

    Essentially, we call our original function `g` and then convert the return from `a` to `b` using `f`.

    Type substitution on `f . g` yields `a -> b . Int -> a` which reduces to `Int -> b`.

    ##Mapping from `a -> Int` to `b -> Int` (#3)

    ```haskell
    newtype F3 a = F3 (a -> Int)

    instance Functor F3 where
    fmap f (F g) = F (???)
    ```

    We may think that `g . f` would work by first converting the input using `f` and then calling the original function `g`.

    Problem is that `f` would need to be `b -> a` which is NOT how functor was defined in #1.

    What we need a different *Functor-like* class that will work with mapping functions with reversed signatures.

    ```haskell
    class Contravariant f where
    contramap :: (b -> a) -> f a -> f b
    ```

    The only difference between `Contravariant` and `Functor` (which is considered `Covariant`) is the mapping function's signature order.

    In `Functor`, it is `a -> b`. In `Contravariant`, it is `b -> a`.

    Now that we have `Contravariant` with its reversed signature, we can write a mapping function for `F3` the way we had originally hoped, i.e. by using `g . f`:

    ```haskell
    instance Contravariant F3 where
    contramap f (F3 g) = F3 (g . f)
    ```

    Compare `F2`'s `instance` (`Functor`) with `F3`'s `instance` (`Contravariant`).

    The only difference is the order the composition of `f` and `g` and the `class` changed from `Functor` to `Contravariant`.

    ## Generalization #1

    Note that mapping from `Int -> a` to `Int -> b` with `a -> b` (#2) used `Functor`, but mapping from `a -> Int` to `b -> Int` with `a -> b` (#3) was not possible and required a mapping function of `b -> a` and `Contravariant`.

    Why? Because the position of the `a` and `b` changed which affects the composition of `f` and `g`.

    At this point, the best generalization that we can make is that for 2 parameters, if the polymophic parameter, in this case `a`, is on the right side then `Functor` should be used.

    And if a function has 2 parameters and the polymorphic parameter is on the left side then `Contravariant` should be used.

    This generalization is far from complete since it is restricted to functions of 2 parameters. Let's continue to look at more complex examples to see if we can get a better understanding of when to use `Functor` and when to use `Contravariant`.

    ##Mapping from `(Int -> Int) -> a` to `(Int -> Int) -> b` (#4)

    If `Generalization #1` is right, then we should use `Functor` since the polymorphic parameter is in the rightmost position.

    ```haskell
    newtype F4 a = F4 ((Int -> Int) -> a)

    instance Functor F4 where
    fmap f (F4 g) = F4 (f . g)
    ```

    Here `g` takes `(Int -> Int)` and returns an `a` into f which takes an `a` and returns a `b`. Now the final result takes a `(Int -> Int)` and returns a `b` which is what we wanted.

    And so far, `Generalization #1` is holding.

    ##Mapping from `(a -> Int) -> Int` to `(b -> Int) -> Int` (#5)

    ```haskell
    newtype F5 a = F5 ((a -> Int) -> Int)
    ```

    Unfortunately, `Generalization #1` doesn't help us here. The left side has 2 parameters of which the leftmost is polymorphic, i.e. `a`, and the rightmost is concrete, i.e. `Int`.

    Looking at past implementations, we see that `f`'s signature is either `a -> b` if we use `Functor` or `b -> a` if we use `Contravariant`. And `g`'s signature is the signature that we're starting with, in this case `(a -> Int) -> Int`.

    Also in the past, we simply composed `f` and `g` but this time `f` has a signature that doesn't compose with `g`. So some sort of simple composition isn't going to work here.

    What we ultimately need is a function that takes a `b -> Int` which will get converted to an `a -> Int` so that it can be applied to the function we started with, i.e. `(a -> Int) -> Int`.

    We know that to convert a `b -> Int` to an `a -> Int` using composition will require an `a -> b` mapping function which tells us that we need a `Functor`.

    So we create a new function, `h`, with a type we can convert, i.e. `b -> Int` and we have `f`, our conversion function convert it. Then we apply that to our original function, `g`, giving us:

    ```haskell
    instance Functor F5 where
    fmap f (F5 g) = F5 (\h -> g (h . f))
    ```

    Lookin at `h` in detail and replacing types and reducing gives us:

    ```
    \h -> g ( h . f )
    (b -> Int) -> (a -> Int) -> Int ( b -> Int . a -> b )
    (b -> Int) -> (a -> Int) -> Int ( a -> Int )
    (b -> Int) -> Int
    ```

    This is exactly what we were aiming for, i.e. `(b -> Int) -> Int`.

    ##Mapping from `(Int -> a) -> Int` to `(Int -> b) -> Int` (#6)

    ```haskell
    newtype F6 a = F6 ((Int -> a) -> Int)
    ```

    This is sort of an inverse of the previous example. So we can expect to use a `Contravariant` instead of a `Functor`.

    And if our past experience is right regarding the differences between the implementation of a `Functor` vs `Contravariant` we'll probably compose reversed in the `Contravariant` compared with the `Functor`.

    Turns out that both patterns hold:

    ```haskell
    instance Contravariant F6 where
    contramap f (F6 g) = F6 (\h -> g (f . h))
    ```

    Lookin at `h` in detail and replacing types and reducing gives us:

    ```
    \h -> g ( f . h )
    (Int -> b) -> (Int -> a) -> Int ( b -> a . Int -> b )
    (Int -> b) -> (Int -> a) -> Int ( Int -> a )
    (Int -> b) -> Int
    ```

    Once again, this is exactly what we were aiming for, i.e. `(Int -> b) -> Int`.

    ## Generalization #2

    Now that we've done some more complex mappings, it's time to revisit `Generalization #1`, which we knew was incomplete.

    When we mapped from `(Int -> Int) -> a` to `(Int -> Int) -> b` (#4), `Generalization #1` was helpful since `a` and `b` were in the rightmost position. As a reminder, we wound up using a `Functor`.

    But when we mapped from `(a -> Int) -> Int` to `(b -> Int) -> Int` (#5), we wound up with a `Functor` even though `a` and `b` were the leftmost of their parenthesis.

    And we used `Contravariant` when we mapped from `(Int -> a) -> Int` to `(Int -> b) -> Int)` (#6) even though `a` and `b` were the rightmost of their parenthesis.

    So a simple rightmost/leftmost model is naive and won't work helping us decide whether we are working with the `Covariant` or `Contravariant` case.

    In fact, the rules seemed to change to the polar opposite every time we enter a parenthetical.

    So let's assume that it flips as we enter parenthesis and see if this flipping continues by mapping with yet another parenthetical group to get a better understanding of when we use a `Covariant` as opposed to a `Contravariant`.

    ##A mapping strategy emerges

    In #2 and #3, the function composed with `f`, our mapping function, has converted either an `a -> Int` to `b -> Int` or an `Int -> a` to `Int -> b`. In those cases that was sufficient since these were simple type mappings.

    It was also sufficient in #4 since it's mapping `(Int -> Int) -> a` can be thought of a just a simple mapping of the form `c -> a`.

    In #5 and #6, however, we had more complex mappings and although we started with `f`, we applied it to an anonymous function `h` that we had to create with the specific type signature that would allow our `f` to replace the `a` with a `b`.

    Then we applied that to the original function to get our final type mapping.

    As we move to more complex mappings, we can expect to use the strategy from #5 and #6 to get us part of the way there.

    ##Mapping from `((a -> Int) -> Int) -> Int` to `((b -> Int) -> Int) -> Int` (#7)

    ```haskell
    newtype F7 a = F7 (((a -> Int) -> Int) -> Int)
    ```

    Let's assume our flipping theory is correct and each time we move from right to left into another parenthesis, the rules for `Covariant` and `Contravariant` switch.

    ```
    (((a -> Int) -> Int) -> Int)
    3 2 1
    ```
    Starting at the rightmost parenthetical (1), we start with `Covariant` being the rightmost side. Then we move leftwards to the next parenthetical (2) and `Contravariant` is rightmost. Then we move one more time to the leftmost parenthetical (3) and the rules flip back to `Covariant` is the rightmost.
    Since we are out of parenthesis and are done flipping, we will assume that the rightmost is `Covariant` and the leftmost is `Contravariant`.
    `a` is in the leftmost position of the final parenthetical group (3), which means that if `Generalization #2` is correct, we will be using `Contravariant`.
    Let's see if that holds.
    We have:
    ```haskell
    newtype F7 a = F7 (((a -> Int) -> Int) -> Int)
    ```

    Since we expect this to be a `Contravariant`, our mapping function `f` is `b -> a`.

    We can also expect that this will look similar to #5 since the leftmost part of the original function signature, `(a -> Int) -> Int` is exactly equal to #5.

    Our `h` must be of type `a -> Int` to compose with `f` as `b -> a`, therefore
    `h . f` is `b -> Int`.

    We cannot apply this to our original function, `((a -> Int) -> Int) -> Int`, like before since this function has an extra `Int` parameter. Also, `h . f` is in terms of `b` not `a`.

    So we must create yet another function, let's call it `hh`, which has the type that we **can** apply `h . f` to that finally returns an `Int`, viz. `(b -> Int) -> Int`.

    So far, we have:

    ```haskell
    \h -> hh(h . f) :: (a -> Int) -> Int
    ```

    which is perfect for applying to our original function `g`, `((a -> Int) -> Int) -> Int` giving us our final solution:

    ```haskell
    newtype F7 a = F7 (((a -> Int) -> Int) -> Int)

    instance Contravariant F7 where
    contramap f (F7 g) = F7 (\hh -> g (\h -> hh(h . f)))
    ```

    Looks like we can keep `Generalization #2` for now. Maybe with enough experience we can further generalize it.

    ##Mapping from `((Int -> a) -> Int) -> Int` to `((Int -> b) -> Int) -> Int` (#8)

    Looking at the pattern of solutions for #5 and #6, we can see that there are 2 difference:

    1. one is `Functor` and the other is `Contravariant`
    2. one uses `h . f` and the other uses `f . h`

    Note that we make no assumption that there is any correlation between 1 and 2 here, i.e. `Functor` doesn't necessarily always use `h . f`. We just want to pick the opposite of whichever one #7 uses to create #8.

    So let's take a stab at this mapping by just applying these 2 inversions to solution for #7, viz.:

    1. `Contravariant` in #7 becomes `Functor`
    2. `h . f` in #7 becomes `f . h`

    ```haskell
    newtype F8 a = F8 (((Int -> a) -> Int) -> Int)

    instance Functor F8 where
    fmap f (F8 g) = F8 (\hh -> g (\h -> hh(f . h)))
    ```

    Turns out that that approach worked great.

    ##Mapping from `(((a -> Int) -> Int) -> Int) -> Int` to `(((b -> Int) -> Int) -> Int) -> Int` (#9)

    At this point, it would be nice at this point if we could just follow some pattern and not have to figure this out type by type.

    Although, it's not a simple pattern, there are some rules to this pattern that arise:

    1. When adding an additional `-> Int`, a `Functor` becomes a `Contravariant`
    2. When dealing with `a -> Int`, `h . f` is used
    3. When dealing with `Int -> a`, `f . h` is used
    4. When adding an additional `-> Int` beyond 2, we have to create an additional anonymous function that we can apply our `h . f` or `f . h` conversion to

    We can see an example of rule #1 when going from #3 (Contravariant) to #5 (Covariant) or #4 (Covariant) to #6 (Contravariant).

    Rule #2 can be seen in #5 and rule #3 in #6.

    Rule #4 has an interesting pattern. Starting with #5, things get complicated but repetitive.

    The `a -> Int` cases:

    - \#3: `(g . f)`
    - \#5: `(\h -> g (h . f))`
    - \#7: `(\hh -> g (\h -> hh(h . f)))`

    The `Int -> a` cases:

    - \#4: `(f . g)`
    - \#6: `(\h -> g (f . h))`
    - \#8: `(\hh -> g (\h -> hh(f . h)))`

    The two cases only differ by the order of composition.

    But as additional `-> Int`'s got added, e.g. moving from #4 to #6, `g` gets *pulled out* and replaced with an anonymous function, we progressively called `h` then `hh`, etc.

    This new construct get applied to `g`, our original function as the final step.

    Then the whole thing is wrapped by this anonymous function.

    If we continue this pattern, we can build #9 with these steps:

    Start with #7, the version with 1 less `-> Int`:

    ```haskell
    (\hh -> g (\h -> hh(h . f)))
    ```

    Pull `g` out and place it front (leaving the hole `_` for now):

    ```haskell
    g (\hh -> _(\h -> hh(h . f)))
    ```

    Replace the hole with a new anonymous function (adding one more `h` to help keep things straight, i.e. `hhh`):

    ```haskell
    g (\hh -> hhh(\h -> hh(h . f)))
    ```

    Then wrapping it up in this new anonymous function, viz. `hhh`:

    ```haskell
    (\hhh -> g (\hh -> hhh(\h -> hh(h . f))))
    ```

    Since #7 is a `Contravariant`, rule #1 would say that #9 will need to be `Functor`.

    So applying our pattern rules and starting with #7 as a starting point, we now have:

    ```haskell
    newtype F9 a = F9 ((((a -> Int) -> Int) -> Int) -> Int)

    instance Functor F9 where
    fmap f (F9 g) = F9 (\hhh -> g (\hh -> hhh(\h -> hh(h . f))))
    ```

    which compiles making us confident that we can continue to build these ad infinitum, e.g. the next few in this iteration are:

    ```haskell
    (\hhhh -> g (\hhh -> hhhh(\hh -> hhh(\h -> hh(h . f)))))
    (\hhhhh -> g (\hhhh -> hhhhh(\hhh -> hhhh(\hh -> hhh(\h -> hh(h . f))))))
    (\hhhhhh -> g (\hhhhh -> hhhhhh(\hhhh -> hhhhh(\hhh -> hhhh(\hh -> hhh(\h -> hh(h . f)))))))
    ```

    All of these `h`'s are making my eyes glaze over. Let's simplify:

    ```haskell
    (\h4 -> g (\h3 -> h4(\h2 -> h3(\h -> h2(h . f)))))
    (\h5 -> g (\h4 -> h5(\h3 -> h4(\h2 -> h3(\h -> h2(h . f))))))
    (\h6 -> g (\h5 -> h6(\h4 -> h5(\h3 -> h4(\h2 -> h3(\h -> h2(h . f)))))))
    ```

    ##Mapping from `(((Int -> a) -> Int) -> Int) -> Int` to `(((Int -> b) -> Int) -> Int) -> Int` (#10)

    Going from #9 to #10 is far easier than going from #7 to #9.

    The rules are simpler (see the pattern rules under #8). The differences here are `Functor` to `Contravariant` (and visa versa) and `h . f` to `f . h` (and visa versa).

    Therefore:

    ```haskell
    newtype F10 a = F10 ((((Int -> a) -> Int) -> Int) -> Int)

    instance Contravariant F10 where
    contramap f (F10 g) = F10 (\hhh -> g (\hh -> hhh(\h -> hh(f . h))))
    ```

    ##Now what?

    No sense in continuing since a pattern has arisen that can be used to generate more and more complex versions.

    Besides, we've long since surpassed any reasonable likelihood that we'll see such signatures in the wild.

    But what about other signature forms?

    ##Mapping from `Int -> Int -> a` to `Int -> Int -> b` (#11)

    This mapping can be written like:

    ```haskell
    Int -> (Int -> a)
    ```
    which are not necessary since arrows, `->`, associate to the right. But it's important to draw them like this for just long enough for use to recognize that we are dealing with the polar opposite signatures than we've been dealing with so far which were asociated to the left.

    But it is clear that these forms are going to be easier to deal with.

    This particular mapping is easy. We simply call the function and then map the results.

    Since we are converting a `return value` of type `a` to be of type `b`, we need a mapping function from `a -> b` which means we need to use `Functor`.

    But first we need a few helper functions written with it's parameters backwards from what would be traditional to help us keep track of our mapping functions `f`:

    ```haskell
    compose2 :: (a -> b -> c) -> (c -> d) -> a -> b -> d
    compose2 g f = (f .) . g

    compose3 :: (a -> b -> c -> d) -> (d -> e) -> a -> b -> c -> e
    compose3 g f = ((f .) .) . g

    compose4 :: (a -> b -> c -> d -> e) -> (e -> f) -> a -> b -> c -> d -> f
    compose4 g f = (((f .) .) .) . g

    compose5 :: (a -> b -> c -> d -> e -> f) -> (f -> g) -> a -> b -> c -> d -> e -> g
    compose5 g f = ((((f .) .) .) .) . g
    ```
    We need `compose2` here but will use the other functions for functions that take more parameters.

    Now we can map:

    ```haskell
    newtype F11 a = F11 (Int -> Int -> a)

    instance Functor F11 where
    fmap f (F11 g) = F11 (compose2 g f)
    ```

    In `compose2`, our mapping function, `f`, is executed last to convert the return of `g` from `a` to `b`.


    ##Mapping from `Int -> a -> Int` to `Int -> b -> Int` (#12)

    Here, we are mapping a `parameter` of type `a` instead of a `return value`, which means we'll need to map the `parameter` from `b` to `a` **before** we call our original function, `g`.

    That requires a mapping function from `b -> a`, telling us that we need to use a `Contravariant`.

    Before we do that though, we'll need some helpers to map our parameters:

    ```haskell
    callMap2of2 :: (b -> a) -> (c -> a -> d) -> c -> b -> d
    callMap2of2 f g x y = g x (f y)

    callMap1of2 :: (b -> a) -> (a -> c -> d) -> b -> c -> d
    callMap1of2 f g x = g (f x)
    ```

    `callMap2of2` will call our original function, `g`, and map the 2nd parameter of a 2 parameters function call.

    `callMap1of2` does the same except it maps the 1st parameter and we'll use it later.

    So our map is:

    ```haskell
    newtype F12 a = F12 (Int -> a -> Int)

    instance Contravariant F12 where
    contramap f (F12 g) = F12 (callMap2of2 f g)
    ```

    ##Mapping from `a -> Int -> Int` to `b -> Int -> Int` (#13)

    Once again we are mapping a `parameter` except the only difference between this mapping and #12 is that `parameter` is the 1st.

    So, we do what we did in #12 except use `callMap1of2` instead:

    ```haskell
    newtype F13 a = F13 (a -> Int -> Int)

    instance Contravariant F13 where
    contramap f (F13 g) = F13 (callMap1of2 f g)
    ```

    ##Mapping from `Int -> ... -> a` to `Int -> ... -> b` (#14)

    This is a general case of #11 and will look something like:

    ```haskell
    -- Pseudocode
    newtype F14 a = F14 (Int -> ... -> a)

    instance Functor F14 where
    fmap f (F14 g) = F14 (composeN g f)
    ```

    where `composeN` is the compose function where `N` is the count of concrete parameters.

    ##Mapping from `a -> ... -> Int` to `b -> ... -> Int` (#15)

    This is the general case of #12 and #13 and will look something like:

    ```haskell
    -- Pseudocode
    newtype F15 a = F15 (a -> ... -> Int)

    instance Contravariant F15 where
    contramap f (F15 g) = F15 (callMapNofM f g)
    ```

    where `callMapNofM` is the parametric mapping function that maps the `N`th parameter of a function of `M` parameters.

    ##Conclusion

    Hopefully, working through all of these examples will help to inform how and when to use `Functor` or `Contravariant`.