Type Systems #16: Functions... on Types?


(This is part 16 in a series on type systems. You can find part 15 here .)

Hmm… okay. So a list of integers has type

IntList =R. R → (IntRR) → R

What about a list of booleans, or strings? Well, those would obviously be

BoolList =R. R → (BooleanRR) → R
StringList =R. R → (StringRR) → R

It feels like we have been here before, all the way back in post #4 when we wanted to define an apply function that was generic in it’s argument. We’re running into the exact define an apply function that was generic in its argument. We’re running into the exact same problem, just at the type level.

I think we’re finally ready to move to the next level of abstraction: Type Operators! It only took us 12 posts. Warning, however: The next few posts are going to up the abstraction a lot, it’s not exactly easily digestible material. Though of course I will try to break it down for you.

Conceptually, type operators should not be a huge leap either, because we use them all the time in regular programming — there we call them simply “generics”, List<T> being an example, or Promise<T>.

To fit them into our theoretical framework, it would be nice to take these three list types we defined above and turn the Int, Boolean, and String parts into a variable.

And usually we parametrize values via functions, right? So can’t we just write, like…

List = λA. ∀R. R → (ARR) → R

And uhm… well, yeah! We can totally do that. We just define functions on the type level! I mean if you squint a little, List<T> also looks like a function call, kind of, but we use angle brackets instead of parentheses.

With our List “type function” we can type our list from last post as

myList :: List Int
myList = cons 1 (cons 2 (cons 3 nil))

which is super elegant I must say. It’s just a function call, truly a very lambda way of approaching the problem. The List thingy is a function that takes a type and returns a type.

This extension to System F is called System Fω — System F omega — and it adds a lambda calculus at the type level. It’s one of the most important and foundational type systems out there, forming the theoretical underpinnings of many modern programming languages.

(This is part 16 in a series on type systems. You can find part 17 here .)