ceylon / ceylon-js

DEPRECATED
Apache License 2.0
54 stars 9 forks source link

support type lambdas that capture generic arguments #561

Open jvasileff opened 9 years ago

jvasileff commented 9 years ago

In the code below, Functor has a generic parameter Container that takes type constructors of the form Container<Element>. This works well for types like Singleton, List, and Set.

Pair is a class with two generic parameters (Pair<A,B>) - one more of course than Container.

In order to satisfy Container with Pair, a type lambda is necessary to resolve this difference. PairLambda performs this task, capturing PairFunctor's A for Pair's first type parameter, and designating Pair's second type parameter as Container's Element.

This type checked code:

class Pair<A,B>() {}

interface Functor<Element, Container> 
        given Container<Element> {

    shared default void doSomething() {
        print(`Element`);
    }
}

class PairFunctor<A, B>() 
        satisfies Functor<B, PairLambda>
        given A satisfies Object {

    shared alias PairLambda<E> => Pair<A,E>;
}

void callDoSomething<Element, Container>
        (Functor<Element, Container> functor)
        given Container<Element> {

    functor.doSomething();
}

shared void testPairFunctor() {
    value functor = PairFunctor<Integer,Float>();
    functor.doSomething();
    callDoSomething(functor);
}

results in:

ceylon.language::Float
snapjs.base-0.0.1.js:5370
$16l1={t:Pair,a:{B$Pair:'E$PairLambda',A$Pair:pairFunctor$.$$targs$$.A$PairFun
                                                                    ^
TypeError: Cannot read property 'A$PairFunctor' of undefined
    at pairFunctor$.PairLambda$PairFunctor (snapjs.base-0.0.1.js:5370:138)
    at testPairFunctor (snapjs.base-0.0.1.js:5385:75)
    at [eval]:1:366

If PairLambda is rewritten to not capture PairFunctor.A, the program works. With:

    shared alias PairLambda<E> => Pair<String,E>;

you get:

ceylon.language::Float
ceylon.language::Float