Code Monkey home page Code Monkey logo

bug-groovy-kinds-type-check's Introduction

bug-groovy-kinds-type-check

Groovy does not have kinds (aka higher order types), see https://en.wikipedia.org/wiki/Kind_(type_theory).

This can be partially simulated by exploiting (abusing?) the Groovy language. Whilst Java does not allow higher order generics this can be done with Groovy 2.3.3.

One of the simples "types" that have this kind is Functor. Intuitively, a functor is a type that hold values that can be transformed (mapped over). Examples include lists, options, sets, and trees. The Functor type has the kind * -> *, that is, a function whose first argument is a type and result is another type.

So invalid code in Java like this:

    interface Functor<T> {
        abstract <A, B> T<B> map(T<A> t, F<A, B> f);
    }

is ok in Groovy (and type checks when it should not).

@TypeChecked
interface Functor<T> {
    abstract <A, B> T<B> map(T<A> t, F<A, B> f)
}

We note that writing Function<T> to express the idea that the generic type T requires a single generic type parameter is invalid Java and Groovy. The definition Groovy accepts of Functor has no restriction on the number of generic type parameters T requires. More on this later.

Lets try to implement the list functor in Groovy:

@TypeChecked
class ListFunctor implements Functor<List> {
    @Override
    def <A, B> List<B> map(List<A> list, F<A, B> f) {
        list.collect { A a ->
            f.f(a)
        }
    }
}

An example of the functor being used is:

  @Test
    void test1() {
        def f = new ListFunctor()
        def list = f.map([1, 2, 3, 4]) { Integer i -> i >= 2 }
        println list
    }

Note that the List type requires a single generic type parameter which matched our definition of the Functor class, in particular the map definition. Let's inspect what happens when the type used does not take a single generic type parameter. Let's use Integer and Map to do so.

The IntegerFunctor can be defined as:

@TypeChecked
class IntegerFunctor implements Functor<Integer> {
    @Override
    def <A, B> Integer map(Integer i, F<A, B> f) {
        i
    }
}

Note that this does not really fit in the definition of Functor. The first parameter to map in functor takes T whereas for IntegerFunctor it takes just an Integer. With no generic type on the generic type to Functor the function from A to B becomes non-sensical. While this compiles with type checking, I don't believe it actually should.

Let's now define a functor for Map, even though Map requires 2 generic type parameters instead of 1 and see what happens.

@TypeChecked
class MapFunctor2 implements Functor<Map> {
    @Override
    def <A, B, C> Map<C, B> map(Map<C, A> fa, F<A, B> f) {
        fa.collectEntries { C k, A a ->
            [k, f.f(a)]
        }
    }
}

Here, we map over the values, keeping the key constant. Despite the mismatch between this map definition and Functor's map definition this code compiles and runs correctly.

T<B> map(T<A> t, F<A, B> f)

Again it looks like the requirement of applying a single generic type to T is not enforced.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.