In response to suggestions from Lambda-the-Ultimate.org members Matt and Mario B. I am pretty much all but decided to go with a new annotation for the Cat type system.
The new proposal is that brackets will only be used to surround function terms, and types will be presented from right to left where the rightmost type represents the top of the stack. So for example the following
eval : ((A:any*) -> (B:any*) A) -> (B)
Will now be written as:
eval : (A (A:any* -> B:any*) -> B)
I have run into some problems though with ambiguitiues in the type system. I won’t get into it in detail for now, but to say that the term [dup] dip eval appears to have an ambiguous typing. This appeared when I tried to construct a derivation tree :
dup : (a:any -> a a)
-------------------
[dup] : ( -> (a:any -> a a)) dip : (A c:any (A:any* -> B:any*) -> B c)
------------------------------------------------------------------------
[dup] dip : (a:any c:any -> a a c) eval : (D (D:any* -> E:any*) -> E)
-----------------------------------------------------------------------
[dup] dip eval : (a:any (D:any* -> E:any*) -> a a E)
At this point there is ambiguity since D may be one of the following:
D = nil | a | a, a | X, a, a
In other words, D may match nothing, the type a, two instances of type a, or more. Depending on what is matched by D will affect the output type of the function.
To be specific consider if D matches nothing then the production (a a E) is correct, but if D matches (a) then the production should be (a E).
I don’t have a solution, but I have some useful observations. First, if I used the following instead of eval:
eval1 : (a (a:any -> b:any) -> b)
This alleviates the confusion, but I don’t know how to best leverage this.
This leads me to my next observation: perhaps I could simply treat all n-ary functions as unary functions, which are curried, in the style of Haskell and ML. So in other words there is an equivalency between (x y -> z) and (x -> y -> z). This could be useful.
This is where I currently stand, I will have to spend some time thinking about the type rules to find an easy way out of this pickle.
Interestingly this corresponds to behaviour in the compiler which I attributed to bugs in my code. The silver lining is knowing that my code was probably correct, and the problems lie in the type system.
Well if nothing else this has definitely taught me the value of formalizing the semantics of type systems.