# Contravariant functors as invariant functors by Mark Seemann

*Another most likely useless set of invariant functors that nonetheless exist.*

This article is part of a series of articles about invariant functors. An invariant functor is a functor that is neither covariant nor contravariant. See the series introduction for more details.

It turns out that all contravariant functors are also invariant functors.

Is this useful? Let me, like in the previous article, be honest and say that if it is, I'm not aware of it. Thus, if you're interested in practical applications, you can stop reading here. This article contains nothing of practical use - as far as I can tell.

### Because it's there #

Why describe something of no practical use?

Why do some people climb Mount Everest? *Because it's there*, or for other irrational reasons. Which is fine. I've no personal goals that involve climbing mountains, but I happily engage in other irrational and subjective activities.

One of them, apparently, is to write articles of software constructs of no practical use, *because it's there*.

All contravariant functors are also invariant functors, even if that's of no practical use. That's just the way it is. This article explains how, and shows a few (useless) examples.

I'll start with a few Haskell examples and then move on to showing the equivalent examples in C#. If you're unfamiliar with Haskell, you can skip that section.

### Haskell package #

For Haskell you can find an existing definition and implementations in the invariant package. It already makes most 'common' contravariant functors `Invariant`

instances, including `Predicate`

, `Comparison`

, and `Equivalence`

. Here's an example of using `invmap`

with a predicate.

First, we need a predicate. Consider a function that evaluates whether a number is divisible by three:

isDivisbleBy3 :: Integral a => a -> Bool isDivisbleBy3 = (0 ==) . (`mod` 3)

While this is already conceptually a contravariant functor, in order to make it an `Invariant`

instance, we have to enclose it in the `Predicate`

wrapper:

ghci> :t Predicate isDivisbleBy3 Predicate isDivisbleBy3 :: Integral a => Predicate a

This is a predicate of some kind of integer. What if we wanted to know if a given duration represented a number of picoseconds divisible by three? Silly example, I know, but in order to demonstrate invariant mapping, we need types that are isomorphic, and NominalDiffTime is isomorphic to a number of picoseconds via its `Enum`

instance.

p :: Enum a => Predicate a p = invmap toEnum fromEnum $ Predicate isDivisbleBy3

In other words, it's possible to map the `Integral`

predicate to an `Enum`

predicate, and since `NominalDiffTime`

is an `Enum`

instance, you can now evaluate various durations:

ghci> (getPredicate p) $ secondsToNominalDiffTime 60 True ghci> (getPredicate p) $ secondsToNominalDiffTime 61 False

This is, as I've already announced, hardly useful, but it's still possible. Unless you have an API that *requires* an `Invariant`

instance, it's also redundant, because you could just have used `contramap`

with the predicate:

ghci> (getPredicate $ contramap fromEnum $ Predicate isDivisbleBy3) $ secondsToNominalDiffTime 60 True ghci> (getPredicate $ contramap fromEnum $ Predicate isDivisbleBy3) $ secondsToNominalDiffTime 61 False

When mapping a contravariant functor, only the contravariant mapping argument is required. The `Invariant`

instances for `Contravariant`

simply ignores the covariant mapping argument.

### Specification as an invariant functor in C# #

My earlier article The Specification contravariant functor takes a more object-oriented view on predicates by examining the Specification pattern.

As outlined in the introduction, while it's possible to add a method called `InvMap`

, it'd be more idiomatic to add a non-standard `Select`

method:

public static ISpecification<T1> Select<T, T1>( this ISpecification<T> source, Func<T, T1> tToT1, Func<T1, T> t1ToT) { return source.ContraMap(t1ToT); }

This implementation ignores `tToT1`

and delegates to the existing `ContraMap`

method.

Here's a unit test that demonstrates an example equivalent to the above Haskell example:

[Theory] [InlineData(60, true)] [InlineData(61, false)] public void InvariantMappingExample(long seconds, bool expected) { ISpecification<long> spec = new IsDivisibleBy3Specification(); ISpecification<TimeSpan> mappedSpec = spec.Select(ticks => new TimeSpan(ticks), ts => ts.Ticks); Assert.Equal( expected, mappedSpec.IsSatisfiedBy(TimeSpan.FromSeconds(seconds))); }

Again, while this is hardly useful, it's possible.

### Conclusion #

All contravariant functors are invariant functors. You simply use the 'normal' contravariant mapping function (`contramap`

in Haskell). This enables you to add an invariant mapping (`invmap`

) that only uses the contravariant argument (`b -> a`

) and ignores the covariant argument (`a -> b`

).

Invariant functors are, however, not particularly useful, so neither is this result. Still, it's there, so deserves a mention. Enough of that, though.

**Next:** Monads.