Type Syntax
Having polymorphic types also reminded me of the fact that, when writing the parser, I ignored most of the type parsing. It turned out to not as easy as I expected to specify a satisfactory language for types. I intended to steal most of it from Haskell again, but since I never specified much complicated types in that language, some aspects of its type parsing rather confused me when I tried to implement them in my own parser.
The biggest problem was the associativity of type "application".
Usually, Maybe a
means "the Maybe
type applied to a
", however,
when occuring in a data definition, like data Foo = Foo Maybe a
,
things are suddenly different, and Maybe
and a
are two separate
arguments to Foo
. My confusion was increased by the fact that
functions work differently in my language, and I wanted to use a
syntax like Int Int -> Int
to specify them.
The Haskell-savvy reader will have noticed, at this point, that I'm a blundering idiot and the rules are really rather simple, and analogous to normal application syntax. When occurring in argument position, other type expressions following a type constructor are sibling arguments, not arguments to the constructor itself.
My function syntax had to be complicated a little, because, if it was
parseable at all, it'd require lookahead. As could be seen in the
previous entry, I ended up using fn a b -> c
, where the fn
keyword
signifies that a function definition is starting. This is lightweight
enough, I guess, and resolves the ambiguity.
The embarassing anecdote here is that at one point I thought I'd need
to delimit type arguments, and decided to use <
and >
to do this.
I immediately proceeded to make the same mistake that C++ makes:
Because >>
is read as a single token, a type like List<List<Int>>
didn't parse. Hey, at least I caught it before releasing a standard.