I'm still struggling with this. Apart from the fact one piece of code
is reversing the order of indices compared to another and I can't
decide which is the right order, there's another internal issue in
the compiler. I want to explain this (mainly so I can understand it
myself :)

Felix has two tuple representations internally, roughly:

        // type
        BTYP_tuple of type list

        // fetch component
        BEXPR_get_n (tuple, index)

is the general form, where index originally had to be a constant integer.
That way:

        get ( (1,"hell","1.3), 1)

has type string. An array is just a tuple, but the representation is different:

        BTYP_array of type * index

where the index is a constant integer. This is the same as a tuple type
except that it allows 10,000 components without blowing the compiler
away.

However the get function for an array has to allow the index
to be an expression (or you cannot write a loop). This is cool,
because the type is always the same. Originally, the implementation
was a C binding, the compiler didn't know anything about it.

 The two things changed. First, I added some array abstractions 
in the form of a type class. So that the various dynamic length
arrays (varray, darray, sarray, dsarray etc etc) could all use
a common syntax and common set of algorithms applied to them
once the basics like "length" and "get" and maybe "set" were defined.

The subscript operation in the abstraction is quite nice. 
It is like this:

        index array
        array . index

For example:

        (1,2,3) . (i + 1)

is just reverse application for

        (i + 1) (1,2,3)

and we define 

        apply: int * array -> basetype

to map the syntax onto an abstract get function.

Conceptually here we're treating an integer applied to an array
as a projection function. This is conceptually the same as a tuple,
except that for arrays the return type is the array base type....

And now the rot starts to set in. If an array is really a special case
of a tuple, the projection functions of both should be the same.
In Felix array is a subtype of tuple: it is not merely an morphism,
but an actual embedding.

It is possible to index a tuple with an expression:

        projection: 3 * (int * string * double) -> int + string + double

is the correct signature for a tuple type int * string * double.
It's a sum type. You have to do a pattern match to extract
the value. Naturally. If the index is a constant, we know
what the sum component is, but  its "just wrong" to use the
fact the index is a constant rather than a general expression
to change the type of the generic projection function.

I got away with this before. Now, with polyadic arrays entering
the picture I did a bit of a cheat.

If you index an array or tuple with an integer, you get the existing
rules. For a tuple not an array, a constant index. For an array
you can use an expression. Both return a value of the type
of the component and that type is known because of the restriction.

To get better behaviour, for arrays (only) I also allow indexing
an array of type 3 with a value of type 3. Such an operation
is safe (cannot exceed bounds). However to make that work
I extended

        BEXPR_get_n (base, index)

to allow an index of a "compact linear type".  The type 3
is a compact linear type. So is 3 * 4 * 5, which is the type
of a tuple.

So now, the compiler is checking that the index has the right
type. If it is a constant integer literal or a compact linear
type, it is cool and the *compiler* implements the array
lookup directly. It's not done in the library now.

If you use an integer expression its done in the library.
In fact it is done by checking the index and coercing
it to a compact linear type and then invoking the compiler
implementation!

But now we have two kinds of indices and one kind is
using "get_n" in the compiler and the other is using
"apply" in the compiler. The apply is getting invoked sometimes
for compact linear types, so my modelling of them now has
to deal with two representations.

To make this even more confusing, types like

        3 * 4 + 6 * 6

are also compact linear types. So the index presentation
has tuple and sums in it and guess what:

        3 * 3

is represent by an array, not a tuple.

So the code is a bit of a mess, especially as some special
cases are singled out for optimisation.

The real problem, however, is that the indexing formula is incorrect:
the right way to index an array should return a sum type which
is then "smashed" to get rid of the sum.

To complicate things even more I've been looking at:

        T ^ N ^ M <=> T ^ (N * M)

but a more basic law is:

        T + T + T + T + T <=> 5 * T

This just says a choice between 5 different T values can be represented
by an index 0 .. 4 of which value you chose, plus the value. It's important
because:

        smash : 5 * T -> T

then throws out the index. (Felix has this operator, its called "case_arg" or 
something, couldn't do pattern matching without it).

So unfortunately, simply "regularising" array operations is jumping the gun.
We need to smash the result of generic projection application, which
means we also need to be able to handle sums of the same type
the same we products of the same type become arrays.


--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS,
MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current
with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft
MVPs and experts. SALE $99.99 this month only -- learn more at:
http://p.sf.net/sfu/learnmore_122412
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to