This is the first part of the HKT series. For your convenience you can find other parts using the links below:
Part 1 — Introduction
Part 2 — Homogenous invoice

Today we will play with higher kinded types in C#. If you have no idea what’s that, you can read about them at:
https://robkuz.github.io/Higher-kinded-types-in-fsharp-Intro-Part-I/
https://medium.com/@JosephJnk/what-is-higher-kinded-polymorphism-6fb2bff183f9
http://ocamllabs.io/higher/lightweight-higher-kinded-polymorphism.pdf

They are not available in .NET yet, there are proposals:
https://github.com/fsharp/fslang-suggestions/issues/175
https://github.com/dotnet/csharplang/issues/339

I am not going to show “best” implementation. Instead, I will just show possible approaches (mostly incorrect) to see how we can emulate higher kinded types (HKT).

Let’s start with the following code:

We have an invoice with list of items. Each item is in some status. Let’s add some of them:

Simple enough. Now let’s create instance:

So we have invoice of started items, each of which is string. Let’s say, that we want to process all items:

We finish the item in this way:

We imagine there could be some more logic, obviously. So let’s run it:

And we can see it works nice.

Are there any problems with this approach? Currently our invoice has strings only. What if we’d like to have different item types? Let’s say we want to have one string and one integer:

Now we initialize it with Invoice< Started< string>, Started< int>> and we are done. That’s terrible (imagine how much changes you’d need to make when adding new field). What we actually need is something like:

And this requires a higher kinded type. We cannot say T< string> in .NET.

So what can we do about it?

For now, let’s get back to invoice of strings and see if we can make it more generic:

Let’s introduce this type:

So instead of saying T< string> we will say Brand< T, string>. This way we flatten the generic type and use normal types, not higher ones. We need some marker types:

And now comes the invoice:

And then we process it in this way:

Looks good. So now we can go with these flattened types. In next part we will see how to avoid Brand type just a little.