So I started adding typed lists to Cat by representing them as functions that push two values on the stack. A value, and the rest of the list. Doing this meant that I could reuse the machinery for typing functions to provide statically typed homogeneous lists. So the cons function for adding a value to a list would have the following type:
cons : (( -> ‘B ’a) ’a -> ( -> ‘B ‘a))
This means that I can simply write:
[1] 2 cons
Which would mean the same thing as
[1 2]
To make the type more manageable I am considering the shorthand notation of [’a] to represent a list of elements of type ‘a:
cons : ([’a] ‘a -> [’a])
Extracting elements is simply the reverse:
uncons : ([’a] -> [’a] ‘a)
Okay, hopefully so far that makes a certain amount of sense. Now the problem comes when I have to deal with the empty list. Consider the following:
[] 1 cons
It is only natural for a programmer to expect this to work, but it won’t type-check! The problem is that [] doesn’t conform to the expected type ( -> ‘B ‘a). This states clearly that something has to be pushed onto the stack. Effectively I need a specialized empty list for every type of list we could have. Now that is kind of what we expect in a Java like language: you construct empty lists by explicitly calling the correct constructor (e.g. new List<Whatever>()). It is just a bit frustrating because programmers used to dynamic languages like Scheme are going to expect a single empty list constructor that works for anything (e.g. ‘()).
So what is a language designer to do? One option is to overload “cons” so that it is actually two functions. One that takes an untyped empty list of any type and returns a new typed unit list, and the other takes a typed list of a specific type. This is the best option I can come up with, but it requires a new language feature: multimethods. In other words I would need Cat to perform dynamic dispatching of functions based not only on names, but on the types of the items on the list.
The other option is to require a special empty list constructor that takes a type as a parameter. For example:
int list new
Which would have the type: ( -> [int]).
This would require a slightly smaller overhaul of the language. I just need to be able to construct types dynamically. I can live with that.
I’d love to hear your thoughts on the Cat mailing list.