Skip to content

sviperll/higher-kinded-java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Higher Kinded Java

I've been experimenting with different encodings and I've come up with some new scheme with the ergonomics I mostly like. It is currently presented in higher-kinded-java repository

Basically it's a highj encoding, but with existential type twist. You can get a taste of using it as a library by looking at the Main.java source code .

I propose the way to use higher-kinded types based on some annotation processor. User code should look like this

@GenerateTypeConstructor
public interface List<T> {
    // Ordinary list definition
}

When you use @GenerateTypeConstructor annotation, new class is generated. ListTypeConstructor class is generated in above example. You can use it like this:

    ListTypeConstructor.Is<?> tyConstrKnowledge = ListTypeConstructor.get;

ListTypeConstructor.Is object is parametrized by a wildcard-argument. This is the major difference from highj. The only way to actually use this object is to capture this wildcard:

    <L extends Type.Contructor> void playWithListType(ListTypeConstructor.Is<L> tyConstrKnowledge) {
    }

    void run() {
        ListTypeConstructor.Is<?> tyConstrKnowledge = ListTypeConstructor.get;
        playWithListType(tyConstrKnowledge);
    }

And after you have captured a wildcard you can use Type.App objects:

    <L extends Type.Contructor> void playWithListType(ListTypeConstructor.Is<L> tyConstrKnowledge) {
        Type.App<L, Integer> typeApp = tyConstrKnowledge.convertToTypeApp(List.of(1, 2, 3));
        List<Integer> list = tyConstrKnowledge.convertToList(typeApp);
    }

    void run() {
        ListTypeConstructor.Is<?> tyConstrKnowledge = ListTypeConstructor.get;
        playWithListType(tyConstrKnowledge);
    }

You can't do it without capturing wildcard into some type-variable.

    void run() {
        ListTypeConstructor.Is<?> tyConstrKnowledge = ListTypeConstructor.get;
        Type.App<?, Integer> typeApp = tyConstrKnowledge.convertToTypeApp(List.of(1, 2, 3));

        // Compile-time error can't unify two different captured types
        List<Integer> list = tyConstrKnowledge.convertToList(typeApp);
    }

So, basically this captured type variable is a proof that Type.App instance is created by the same type-constructor-is-object and can be safely transformed back into a List. And you can't do anything without capturing since ListTypeConstructor.get field is actually parametrized with wildcard-type-argument.

Having this framework at your disposal it's easy to get your Monads with type-safe implementations ( List , Optional )

Rawtypes, manual instantiation of Type.App class and plain old casts can all circumvernt type-safety and cause ClassCastException But rawtypes and casts are expected to be unsafe.

Manual instantiation of Type.App class can be made visibly unsafe with methods like

    protected abstract void pleaseDoNotImplementMeItIsUnsafe();

(see actual definition).

Very simple annotation processor as one implemented with writejava4me is sufficient to make this all work.

Try it yourself!

reddit descussion

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published