# The Const functor by Mark Seemann

*Package a constant value, but make it look like a functor. An article for object-oriented programmers.*

This article is an instalment in an article series about functors. In previous articles, you've learned about useful functors such as Maybe and Either. You've also seen at least one less-than useful functor: The Identity functor. In this article, you'll learn about another (practically) useless functor called *Const*. You can skip this article if you want.

Like Identity, the Const functor may not be that useful, but it nonetheless exists. You'll probably not need it for actual programming tasks, but knowing that it exists, like Identity, can be a useful as an analysis tool. It may help you quickly evaluate whether a particular data structure affords various compositions. For example, it may enable you to quickly identify whether, say, a constant type and a list may compose to a functor.

This article starts with C#, then proceeds over F# to finally discuss Haskell's built-in Const functor. You can just skip the languages you don't care about.

### C# Const class #

While C# supports records, and you can implement Const as one, I here present it as a full-fledged class. For readers who may not be that familiar with modern C#, a normal class may be more recognizable.

public sealed class Const<T1, T2> { public T1 Value { get; } public Const(T1 value) { Value = value; } public Const<T1, TResult> Select<TResult>(Func<T2, TResult> selector) { return new Const<T1, TResult>(Value); } public override bool Equals(object obj) { return obj is Const<T1, T2> @const && EqualityComparer<T1>.Default.Equals(Value, @const.Value); } public override int GetHashCode() { return -1584136870 + EqualityComparer<T1>.Default.GetHashCode(Value); } }

The point of the Const functor is to make a constant value look like a functor; that is, a container that you can map from one type to another. The difference from the Identity functor is that Const doesn't allow you to map the constant. Rather, it cheats and pretends having a mappable type that, however, has no value associated with it; a phantom type.

In `Const<T1, T2>`

, the `T2`

type parameter is the 'pretend' type. While the class contains a `T1`

value, it contains no `T2`

value. The `Select`

method, on the other hand, maps `T2`

to `TResult`

. The operation is close to being a no-op, but still not quite. While it doesn't do anything particularly practical, it *does* change the type of the returned value.

Here's a simple example of using the `Select`

method:

Const<string, double> c = new Const<string, int>("foo").Select(i => Math.Sqrt(i));

The new `c`

value *also* contains `"foo"`

. Only its type has changed.

If you find this peculiar, think of it as similar to mapping an empty list, or an empty Maybe value. In those cases, too, no *values* change; only the type changes. The difference between empty Maybe objects or empty lists, and the Const functor is that Const isn't empty. There *is* a value; it's just not the value being mapped.

### Functor laws #

Although the Const functor doesn't really do anything, it still obeys the functor laws. To illustrate it (but not to prove it), here's an FsCheck property that exercises the first functor law:

[Property(QuietOnSuccess = true)] public void ConstObeysFirstFunctorLaw(int i) { var left = new Const<int, string>(i); var right = new Const<int, string>(i).Select(x => x); Assert.Equal(left, right); }

If you think it over for a minute, this makes sense. The test creates a `Const<int, string>`

that contains the integer `i`

, and then proceeds to map *the string that isn't there* to 'itself'. Clearly, this doesn't change the `i`

value contained in the `Const<int, string>`

container.

In the same spirit, a property demonstrates the second functor law:

[Property(QuietOnSuccess = true)] public void ConstObeysSecondFunctorLaw( Func<string, byte> f, Func<int, string> g, short s) { Const<short, byte> left = new Const<short, int>(s).Select(g).Select(f); Const<short, byte> right = new Const<short, int>(s).Select(x => f(g(x))); Assert.Equal(left, right); }

Again, the same kind of almost-no-op takes place. The `g`

function first changes the `int`

type to `string`

, and then `f`

changes the `string`

type to `byte`

, but no *value* ever changes; only the second type parameter. Thus, `left`

and `right`

remain equal, since they both contain the same value `s`

.

### F# Const #

In F# we may idiomatically express Const as a single-case union:

type Const<'v, 'a> = Const of 'v

Here I've chosen to name the first type parameter `'v`

(for *value*) in order to keep the 'functor type parameter' name `'a`

. This enables me to meaningfully annotate the functor mapping function with the type `'a -> 'b`

:

module Const = let get (Const x) = x let map (f : 'a -> 'b) (Const x : Const<'v, 'a>) : Const<'v, 'b> = Const x

Usually, you don't need to annotate F# functions like `map`

, but in this case I added explicit types in order to make it a recognizable functor map.

I could also have defined `map`

like this:

// 'a -> Const<'b,'c> -> Const<'b,'d> let map f (Const x) = Const x

This still works, but is less recognizable as a functor map, since `f`

may be any `'a`

. Notice that if type inference is left to its own devices, it names the input type `Const<'b,'c>`

and the return type `Const<'b,'d>`

. This also means that if you want to supply `f`

as a mapping function, this is legal, because we may consider `'a ~ 'c -> 'd`

. It's still a functor map, but a less familiar representation.

Similar to the above C# code, two FsCheck properties demonstrate that the `Const`

type obeys the functor laws.

[<Property(QuietOnSuccess = true)>] let ``Const obeys first functor law`` (i : int) = let left = Const i let right = Const i |> Const.map id left =! right [<Property(QuietOnSuccess = true)>] let ``Const obeys second functor law`` (f : string -> byte) (g : int -> string) (s : int16) = let left = Const s |> Const.map g |> Const.map f let right = Const s |> Const.map (g >> f) left =! right

The assertions use Unquote's `=!`

operator, which I usually read as *should equal* or *must equal*.

### Haskell Const #

The Haskell base library already comes with a Const `newtype`

.

You can easily create a new `Const`

value:

ghci> Const "foo" Const "foo"

If you inquire about its type, GHCi will tell you in a rather verbose way that the first type parameter is `String`

, but the second may be any type `b`

:

ghci> :t Const "foo" Const "foo" :: forall {k} {b :: k}. Const String b

You can also map by 'incrementing' its non-existent second value:

ghci> (+1) <$> Const "foo" Const "foo" ghci> :t (+1) <$> Const "foo" (+1) <$> Const "foo" :: Num b => Const String b

While the value remains `Const "foo"`

, the type of `b`

is now constrained to a Num instance, which follows from the use of the `+`

operator.

### Functor law proofs #

If you look at the source code for the `Functor`

instance, it looks much like its F# equivalent:

instance Functor (Const m) where fmap _ (Const v) = Const v

We can use equational reasoning with the notation that Bartosz Milewski uses to prove that both functor laws hold, starting with the first:

fmap id (Const x) = { definition of fmap } Const x

Clearly, there's not much to that part. What about the second functor law?

fmap (g . f) (Const x) = { definition of fmap } Const x = { definition of fmap } fmap g (Const x) = { definition of fmap } fmap g (fmap f (Const x)) = { definition of composition } (fmap g . fmap f) (Const x)

While that proof takes a few more steps, most are as trivial as the first proof.

### Conclusion #

The Const functor is hardly a programming construct you'll use in your day-to-day work, but the fact that it exists can be used to generalize some results that involve functors. Now, whenever you have a result that involves a functor, you know that it also generalizes to constant values, just like the Identity functor teaches us that 'naked' type parameters can be thought of as functors.

To give a few examples, we may already know that `Tree<T>`

(C# syntax) is a functor, but a 'naked' generic type parameter `T`

also gives rise to a functor (Identity), as does a non-generic type (such as `int`

or `MyCustomClass`

).

Thus, if you have a function that operates on any functor, it may also, conceivably, operate on data structures that have non-generic types. This may for example be interesting when we begin to consider how functors compose.

**Next:** The State functor.