There is a problem with operators like +, - and * which are both
infix and prefix. When you write

        a - b

the parser knows you mean infix. But what about:

        - (a,b)

Is this the prefix operator applied to pair, or is it the infix
operator?

Normally you wouldn't define an single argument operator on a tuple,
so if you write:

        fun - (a:int) => .. // negative of a
        fun - (a:int, b:int) =>  .. // subtraction

it's all clear. We actually have two functions here named "-"
which overload on a single argument, of types:

        int

and

        int * int


So everything works .. until you get to type classes.

Then it all falls apart. Consider:

        class X[T] {
                fun - (a:T) => ..
                fun - (a:T,b:T) => ...
        }

        open[K]  X[K];
        var x = - (1,1); // WOOPS!

The open statement makes

        fun -[T] : T -> ... // T = int * int
        fun -[T] : T * T .. // T = int

visible and so the call is ambiguous. Even if you write:

        - of (int * int) (1,1)

it doesn't help because both specialisations lead to that signature.

This problem cannot happen in a type class itself, because T inside
the class is not a type variable: it is existentially quantified not
universally quantified internally, which means it is just an unknown
abstract type, not a variable.

That's the difference between classes and modules.
In particular:

        class X {
                fun -[T] (a:T) => ..
                fun -[T] (a:T,b:T) => ..

is NOT the same as the original class X I showed. This class is 
a  module, it isn't polymorphic, the individual functions are
universally quantified, that is, they're polymorphic. 

In the former case the whole class is universally quantified 
and polymorphic but the individual functions are monomorphic.
For them T is just a single unknown type, the same T everywhere.

However when you do:

        open[K] X[K];

you're making all classes X with parameter K available, which means
all specialisations of the functions. Which ensures all calls to 
operator - with a pair argument are ambiguous.

You may never have seen such an open statement .. but this 
one is syntactic sugar for it, and is equivalent:

        open X;

The moral of the story is: do NOT use the same operator name to define
a prefix and infix function.

Now, this does NOT mean we cannot write

        - 1 and 1 - 1

and have it work. The parser knows which function it is.
But it generates 

        -1 and - (1,1)

at the moment. 

In the old days, operator symbols couldn't be function names. 
Instead we had

        class X [T] {
                fun neg (a:T) => ...
                fun add (a:T,b:T) => ..


that is, the names were distinguished. The problem there was you had
to KNOW the mapping made by the parser. You had to know
prefix * mapped to a function named "deref".

So I allowed operator names as identifiers and changed the parser
and thus dug myself into a hole.

I could got back to "neg". Another solution is:

        prefix - (a:int) => ....
        infix - (a:int, b:int) => 

Another tricker solution:

        fun (a:int) - (b:int) => ...

although I can't see how this fits with the grammar for lambdas or
C++ bindings.
 
It's almost possible to do this:

        fun (a:int) - (b:int) / (c:int) => ...

i.e. provide a pattern. This is, after all, exactly what reduce does.
The only trick is that reductions aren't guaranteed to be provided.
Still .. it looks really cool!


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




------------------------------------------------------------------------------
Want excitement?
Manually upgrade your production database.
When you want reliability, choose Perforce
Perforce version control. Predictably reliable.
http://pubads.g.doubleclick.net/gampad/clk?id=157508191&iu=/4140/ostg.clktrk
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to