Skip to content

Higher Kinded Polymorphism / Generics on Generics #2212

Closed
@diab0l

Description

@diab0l

tl;dr

Haskell has monads
Monads are like bacon
C# needs bacon

Introduction

I have a mad craving for higher kinded polymorphism in C#.
And I have no blog to call my own, so here's an essay on this stuff.

That's a fancy name with a lot of crazy type theory and papers behind it, but if you have an understanding of how generic types work in C#, the concept is not terribly hard to understand.

What C# with a taste of bacon would look like

public static T<A> To<T, A>(this IEnumerable<A> xs)
    where T : <>, new(), ICollection<> 
{
    var ta = new T<A>();
    foreach(var x in xs) {
        ta.Add(x);
    }
    return ta;
}

...
{
    var data = Enumerable.Range(0, 20);

    var set = data.To<HashSet<>, int>(); // sorcery!
    var linkedList = data.To<LinkedList<>, int>();
    var list = data.To<List<>, int>();
}

What is going on here?

where T : <>,           // 1
          new(),        // 2
          ICollection<> // 3
  1. T is constrained to be a generic type definition with one type parameter.
    • In CLR lingo: T is a generic type of arity 1
    • In type theory lingo: T is a type constructor of kind * -> *
  2. Also it should have a default constructor
  3. And it should implement ICollection<> (meaning for each type X, T<X> implements ICollection<X>)

Using this you could convert an IEnumerable<T> to any other type that is a collection.
Even all the ones you have never thought about, including the weird ones from libraries which do not get a whole lot of support because nobody uses them (except of course you).

Like HashSet (such a weird collection) or LinkedList (you would need to be crazy).
They are fine citizens of System.Collections.Generic and very useful, yet they don't get the love they deserve, because they are not as famous as List<> and implementing To...() methods in Linq for all of them would be a painful task.

However, with higher kinded polymorphism, they could all get a general concise implementation.

Where's the rest of that bacon?

That general conversion function is just the tip of the iceberg.
You can do all kinds of crazy transformations with higher kinded polymorphism.
And since it allows for such lovely abstractions you only have to implement them once.

Or better yet: Somebody else implements them in a NuGet package and you don't need to care.
Composition over coding.

Haskell? Is that a dog's name?

That NuGet package could be called something neat and concise like, say, Prelude. Yes, what a fine name!
There are some other party poopers, but the lack of Higher Kinded Polymorphism is the biggest road block in stealing all the juicy bacon from the Haskell community.

You know how Linq is awesome?
Do you also know how Linq is an implementation of the List Monad? (kind of)
Well, there are lots of more Monads in Prelude and most of them are awesome.
And currently a bitch to implement in C#.

Plus, HKP would allow to abstract on the concept of Monads!
And on concepts like Tuples (never heard of them), Functors (not what you're thinking), Arrows, Categories and all the crazy math that comes with them.

I've put together a gist of how wonderful this would be in combination with some other features for implementing Maybe.

I don't know what you're talking about, but it sounds expensive

Let's first look at a summary of the benefits that HKP would bring to C#

  1. This feature would make C# the most relevant functional programming language with sub-typing and strong static type checking
  2. A natural extension to the work done by the Linq team
  3. A natural extension to generics
  4. Much more natural porting of Haskell code (think about it: years upon years of research on bacon finally in a consumable form)
  5. A real implementation of the Maybe monad (about time)
  6. More expressiveness without sacrificing static typing
  7. HKPs allow something kind of Meta-programming without the nonsense. Whoever used C++ before knows how easily template programming becomes a nightmare. On the other hand, Haskell programmers are delighted by their juicy type system.
  8. Have I mentioned bacon?

Now let's talk about work:

  • Before anything else, a proper implementation would require CLR support
    • That would be quite involved, but not impossible. Also I believe it can be implemented as a strict extension to the current metadata without breaking existing libraries
    • As a consequence, the F# crowd would benefit from this. I bet they are overjoyed to hear about bacon
    • As another consequence, implementing Haskell on top of .Net would be much less of a pain
  • C# Syntax
    • In C# we can already refer to generic type definitions in typeof() as in typeof(IDictionary<,>)
    • I think the where T : <,> clause seems neat, but is probably not powerful enough (no way to constrain variance on T's parameters or 'swap' parameters for implementations)
      • maybe more like where T<,> : <U, X>, IDictionary<X, U>
      • or rather void Foo<A<B, C>, D>() where A<B, C> : IDictionary<C, B> where B : class
    • Well, the syntax needs work.
  • Type checking
    • it's not work if it's fun

But I'm a vegetarian

Think of Bacon as an abstract higher kinded type class with non-carnivorous implementations

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions