A most likely useless set of invariant functors that nonetheless exist.

It turns out that all functors are also invariant functors.

Is this useful? Let me 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 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.

For Haskell you can find an existing definition and implementations in the invariant package. It already makes most common functors `Invariant` instances, including `[]` (list), `Maybe`, and `Either`. Here's an example of using `invmap` with a small list:

```ghci> invmap secondsToNominalDiffTime nominalDiffTimeToSeconds [0.1, 60]
[0.1s,60s]```

Here I'm using the time package to convert fixed-point decimals into `NominalDiffTime` values.

How is this different from normal functor mapping with `fmap`? In observable behaviour, it's not:

```ghci> fmap secondsToNominalDiffTime [0.1, 60]
[0.1s,60s]```

When invariantly mapping a functor, only the covariant mapping function `a -> b` is used. Here, that's `secondsToNominalDiffTime`. The contravariant mapping function `b -> a` (`nominalDiffTimeToSeconds`) is simply ignored.

While the invariant package already defines certain common functors as `Invariant` instances, every `Functor` instance can be converted to an `Invariant` instance. There are two ways to do that: `invmapFunctor` and `WrappedFunctor`.

In order to demonstrate, we need a custom `Functor` instance. This one should do:

`data Pair a = Pair (a, a) deriving (Eq, Show, Functor)`

If you just want to perform an ad-hoc invariant mapping, you can use `invmapFunctor`:

```ghci> invmapFunctor secondsToNominalDiffTime nominalDiffTimeToSeconds \$ Pair (0.1, 60)
Pair (0.1s,60s)```

I can't think of any reason to do this, but it's possible.

`WrappedFunctor` is perhaps marginally more relevant. If you run into a function that takes an `Invariant` argument, you can convert any `Functor` to an `Invariant` instance by wrapping it in `WrappedFunctor`:

```ghci> invmap secondsToNominalDiffTime nominalDiffTimeToSeconds \$ WrapFunctor \$ Pair (0.1, 60)
WrapFunctor {unwrapFunctor = Pair (0.1s,60s)}```

A realistic, useful example still escapes me, but there it is.

### Pair as an invariant functor in C# #

What would the above Haskell example look like in C#? First, we're going to need a `Pair` data structure:

```public sealed class Pair<T>
{
public Pair(T x, T y)
{
X = x;
Y = y;
}

public T X { get; }
public T Y { get; }

// More members follow...```

Making `Pair<T>` a functor is so easy that Haskell can do it automatically with the `DeriveFunctor` extension. In C# you must explicitly write the function:

```public Pair<T1> Select<T1>(Func<T, T1> selector)
{
return new Pair<T1>(selector(X), selector(Y));
}```

An example equivalent to the above `fmap` example might be this, here expressed as a unit test:

```[Fact]
public void FunctorExample()
{
Pair<long> sut = new Pair<long>(
TimeSpan.TicksPerSecond / 10,
TimeSpan.TicksPerSecond * 60);
Pair<TimeSpan> actual = sut.Select(ticks => new TimeSpan(ticks));
Assert.Equal(
new Pair<TimeSpan>(
TimeSpan.FromSeconds(.1),
TimeSpan.FromSeconds(60)),
actual);
}```

You can trivially make `Pair<T>` an invariant functor by giving it a function equivalent to `invmap`. As I outlined in the introduction it's possible to add an `InvMap` method to the class, but it might be more idiomatic to instead add a `Select` overload:

```public Pair<T1> Select<T1>(Func<T, T1> tToT1, Func<T1, T> t1ToT)
{
return Select(tToT1);
}```

Notice that this overload simply ignores the `t1ToT` argument and delegates to the normal `Select` overload. That's consistent with the Haskell package. This unit test shows an examples:

```[Fact]
public void InvariantFunctorExample()
{
Pair<long> sut = new Pair<long>(
TimeSpan.TicksPerSecond / 10,
TimeSpan.TicksPerSecond * 60);
Pair<TimeSpan> actual =
sut.Select(ticks => new TimeSpan(ticks), ts => ts.Ticks);
Assert.Equal(
new Pair<TimeSpan>(
TimeSpan.FromSeconds(.1),
TimeSpan.FromSeconds(60)),
actual);
}```

I can't think of a reason to do this in C#. In Haskell, at least, you have enough power of abstraction to describe something as simply an `Invariant` functor, and then let client code decide whether to use `Maybe`, `[]`, `Endo`, or a custom type like `Pair`. You can't do that in C#, so the abstraction is even less useful here.

### Conclusion #

All functors are invariant functors. You simply use the normal functor mapping function (`fmap` in Haskell, `map` in many other languages, `Select` in C#). This enables you to add an invariant mapping (`invmap`) that only uses the covariant argument (`a -> b`) and ignores the contravariant argument (`b -> a`).

Invariant functors are, however, not particularly useful, so neither is this result. Still, it's there, so deserves a mention. The situation is similar for the next article.

### Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or somewhere else with a permalink. Ping me with the link, and I may respond.

#### Published

Monday, 26 December 2022 13:05:00 UTC

#### Tags

"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!
Published: Monday, 26 December 2022 13:05:00 UTC