Haskell has concise and extremely rich support for strongly typed
data structures  (this is what allows PIL to be represented and
manipulated so easily).  

The key to strongly typed data structures are Haskell's polymorphic data types:

    data Foo = A | B | C Bar | D Bar Baz

The same declaration can be written with explicitly typed constructor
functions:

    data Foo where
        A :: Foo                -- leaf
        B :: Foo                -- leaf
        C :: Bar -> Foo         -- unary node
        D :: Bar -> Baz -> Foo  -- binary node

Haskell's types can take types as parameters, so you can specify necessary
agreement.  This technique is known as GADT (Generalised Algebraic Data Types):

    data Tree a where
        Zero    :: Tree Int
        Succ    :: Tree Int -> Tree Int
        Pred    :: Tree Int -> Tree Int
        IsZero  :: Tree Int -> Tree Bool
        Cond    :: Tree Bool -> Tree a -> Tree a -> Tree a

One of the keys to these structures' usability is their conciseness.  Currently
in Perl 6, each line in the example above uses six or more lines of Perl.  This
draws attention away from the structure and to the nitty-gritty unimportant
details.

With generic roles, we may be able to write something like this:

    role Tree[::a] { }
    class Zero   does Tree[Int]  { }
    class Succ   does Tree[Int]  { has Tree[Int] $.in }
    class Pred   does Tree[Int]  { has Tree[Int] $.in }
    class IsZero does Tree[Bool] { has Tree[Int] $.in }
    class Cond   does Tree[::a]  {
        has Tree[Bool] $.cond;
        has Tree[a] ($.if, $.else)
    }

The last line is the key.  The a type should be inferred from the constructor.
The trouble with this is that it doesn't provide any type safety.  In the case
of a type conflict, "a" just degenerates to the Any type.

~~~~~~~~~~~~~

During weak type inferrence, the compiler is trying to find the smallest set
that the value could be a member of.  But perhaps it would be possible to
specify a "cap" that, if the compiler tried to generalize beyond that, it would
die.

Perhaps an enum would specify a set of disjoint base types, for instance:

    enum Foo is disjoint {
        A, B, C
    }

Then if the compiler ever tried to generalize into Foo, it would die, such as
if you had an A in the same type variable as a B.  The question is what happens
if it tries to generalize beyond Foo instantly, such as A and Str.  Perhaps you
would have to declare it to be Foo in order to strongly type it.

You would have to specify, then:

    class Cond[Foo ::a] {...}

Which, for long Foo, is beginning to lose the benefits of type inferrence  (but not
of recursively polymorphic types).

~~~~~~~~~~~~~

Hmm... out-of-band type classes are trivial:

    type CommitterILike ::= PugsCommitter | ParrotCommitter;

~~~~~~~~~~~~~

It is an unfortunate use of the :: sigil to specify undeclared types, because
we have no way to refer to a type variable.  Is ::a a type variable or the name
of an 'a' type that has yet to be declared.

It looks like the current thinking is that ::a is always a type variable, with
:: behaving as a sigil.  You cannot use :: as an inline predeclarator  (we
might use "class" for that like C++, or we might just require predeclaration).

~~~~~~~~~~~~~

Perhaps we can make use of the units mechanism for closed data constructors.
Taking the awful "data" declarator from haskell (and introducing another awful
keyword, "kind"), perhaps we have:

    data StrPos {
        kind `bytes:(Int);
        kind `lexemes:(Int);
        kind `codepoints:(Int);
        kind `graphemes:(Int);
    }

("of StrPos" is implied on each of those)

Then:

    $str.pos += 4`bytes;

Is just short for:

    $str.pos += `bytes(4);

And in a signature:

    sub foo ($x`bytes) {...}

Is short for:

    sub foo (`bytes:($x)) {...}   # note the colon

More interestingly, we have:

    data Tree[::a] {
        kind `zero:()            of Tree[Int];
        kind `succ:(Tree[Int])   of Tree[Int];
        kind `pred:(Tree[Int])   of Tree[Int];
        kind `iszero:(Tree[Int]) of Tree[Bool];
        kind `cond:(Tree[Bool], Tree[::a], Tree[::a]) of Tree[::a];
    }

Mmm... nice and concise.

Then, to write visitors, you can use multis:

    multi run (Tree[::a]) of ::a {...}
    multi run (`zero)     { 0 }
    multi run ($v`succ)   { run($v) + 1 }
    multi run ($v`pred)   { run($v) - 1 }
    multi run ($v`iszero) { run($v) == 0 }
    multi run (`cond:($c, $true, $false)) {
        run($c) ?? run($true) :: run($false);
    }

Hmmm.. this imples some sort of signature-signature binding.  What I'd
like to see is:

    data Foo {
        kind `bar:(Int $baz, Int $quux);
    }

    sub run(`bar:(quux => $q, baz => $b)) {...}

For named binding.
