Higher-kinded generics in Java

后端 未结 5 931
别跟我提以往
别跟我提以往 2020-12-05 13:07

Suppose I have the following class:

public class FixExpr {
  Expr in;
}

Now I want to introduce a generic argument, abstract

相关标签:
5条回答
  • 2020-12-05 13:44

    I think what you're trying to do is simply not supported by Java generics. The simpler case of

    public class Foo<T> {
        public T<String> bar() { return null; }
    }
    

    also does not compile using javac.

    Since Java does not know at compile-time what T is, it can't guarantee that T<String> is at all meaningful. For example if you created a Foo<BufferedImage>, bar would have the signature

    public BufferedImage<String> bar()
    

    which is nonsensical. Since there is no mechanism to force you to only instantiate Foos with generic Ts, it refuses to compile.

    0 讨论(0)
  • 2020-12-05 13:46

    It looks as if you may want something like:

    public class Fix<F extends Fix<F>> {
        private F in;
    }
    

    (See the Enum class, and questions about its generics.)

    0 讨论(0)
  • 2020-12-05 13:55

    Maybe you can try Scala, which is a functional language running on JVM, that supports higher-kinded generics.


    [ EDIT by Rahul G ]

    Here's how your particular example roughly translates to Scala:

    trait Expr[+A]
    
    trait FixExpr {
      val in: Expr[FixExpr]
    }
    
    trait Fix[F[_]] {
      val in: F[Fix[F]]
    }
    
    0 讨论(0)
  • 2020-12-05 14:04

    In order to pass a type parameter, the type definition has to declare that it accepts one (it has to be generic). Apparently, your F is not a generic type.

    UPDATE: The line

    F<Fix<F>> in;
    

    declares a variable of type F which accepts a type parameter, the value of which is Fix, which itself accepts a type parameter, the value of which is F. F isn't even defined in your example. I think you may want

    Fix<F> in;
    

    That will give you a variable of type Fix (the type you did define in your example) to which you are passing a type parameter with value F. Since Fix is defined to accept a type parameter, this works.

    UPDATE 2: Reread your title, and now I think you might be trying to do something similar to the approach presented in "Towards Equal Rights for Higher-Kinded Types" (PDF alert). If so, Java doesn't support that, but you might try Scala.

    0 讨论(0)
  • 2020-12-05 14:06

    Still, there are ways to encode higer-kinded generics in Java. Please, have a look at higher-kinded-java project.

    Using this as a library, you can modify your code like this:

    public class Fix<F extends Type.Constructor> {
        Type.App<F, Fix<F>> in;
    }
    

    You should probably add an @GenerateTypeConstructor annotation to your Expr class

    @GenerateTypeConstructor
    public class Expr<S> {
        // ...
    }
    

    This annotation generates ExprTypeConstructor class. Now you can process your Fix of Expr like this:

    class Main {
        void run() {
            runWithTyConstr(ExprTypeConstructor.get);
        }
    
        <E extends Type.Constructor> void runWithTyConstr(ExprTypeConstructor.Is<E> tyConstrKnowledge) {
            Expr<Fix<E>> one = Expr.lit(1);
            Expr<Fix<E>> two = Expr.lit(2);
    
            // convertToTypeApp method is generated by annotation processor
            Type.App<E, Fix<E>> oneAsTyApp = tyConstrKnowledge.convertToTypeApp(one);
            Type.App<E, Fix<E>> twoAsTyApp = tyConstrKnowledge.convertToTypeApp(two);
    
            Fix<E> oneFix = new Fix<>(oneAsTyApp);
            Fix<E> twoFix = new Fix<>(twoAsTyApp);
    
            Expr<Fix<E>> addition = Expr.add(oneFix, twoFix);
            process(addition, tyConstrKnowledge);
        }
    
        <E extends Type.Constructor> void process(
                Fix<E> fixedPoint,
                ExprTypeConstructor.Is<E> tyConstrKnowledge) {
    
            Type.App<E, Fix<E>> inTyApp = fixedPoint.getIn();
    
            // convertToExpr method is generated by annotation processor
            Expr<Fix<E>> in = tyConstrKnowledge.convertToExpr(inTyApp);
    
            for (Fix<E> subExpr: in.getSubExpressions()) {
                process(subExpr, tyConstrKnowledge);
            }
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题