首页 文章

Java中更高级的泛型

提问于
浏览
30

假设我有以下课程:

public class FixExpr {
  Expr<FixExpr> in;
}

现在我想介绍一个泛型参数,抽象使用Expr:

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

但Eclipse并不喜欢这样:

F型不是通用的;它不能用参数<Fix <F >>进行参数化

这是可能的还是我忽略了导致这个特定实例破坏的东西?

一些背景信息:在Haskell中,这是编写泛型函数的常用方法;我正在尝试将其移植到Java . 上例中的类型参数F具有类型* - > 而不是通常的类型 . 在Haskell中它看起来像这样:

newtype Fix f = In { out :: f (Fix f) }

5 回答

  • 25

    我认为你想要做的就是Java泛型不支持 . 更简单的情况

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

    也不使用javac编译 .

    由于Java在编译时不知道 T 是什么,因此无法保证 T<String> 完全有意义 . 例如,如果您创建了 Foo<BufferedImage> ,则 bar 将具有签名

    public BufferedImage<String> bar()
    

    这是荒谬的 . 由于没有机制强制您仅使用泛型 T 实例化 Foo ,因此它拒绝编译 .

  • 24

    也许你可以尝试Scala,它是一种在JVM上运行的函数式语言,支持更高级的泛型 .


    [ EDIT by Rahul G ]

    以下是您的特定示例粗略转换为Scala的方式:

    trait Expr[+A]
    
    trait FixExpr {
      val in: Expr[FixExpr]
    }
    
    trait Fix[F[_]] {
      val in: F[Fix[F]]
    }
    
  • 5

    为了传递一个类型参数,类型定义必须声明它接受一个(它必须是通用的) . 显然,您的 F 不是通用类型 .

    更新:线

    F<Fix<F>> in;
    

    声明一个类型 F 的变量,它接受一个类型参数,其值为 Fix ,它本身接受一个类型参数,其值为 F . F 甚至没有在您的示例中定义 . 我想你可能想要

    Fix<F> in;
    

    这将为您提供一个类型为 Fix 的变量(您在示例中定义的类型),您将向其传递值为 F 的类型参数 . 由于 Fix 被定义为接受类型参数,因此这是有效的 .

    更新2:重新阅读您的 Headers ,现在我认为您可能正在尝试执行与"Towards Equal Rights for Higher-Kinded Types"(PDF警报)中提供的方法类似的操作 . 如果是这样,Java不支持,但您可以尝试使用Scala .

  • 0

    仍然有一些方法可以用Java编码高质量的泛型 . 请看higher-kinded-java project .

    使用它作为库,您可以像这样修改代码:

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

    您应该在 Expr 类中添加 @GenerateTypeConstructor 注释

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

    此批注生成ExprTypeConstructor类 . 现在您可以像这样处理您的Expr修复:

    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);
            }
        }
    
    }
    
  • 1

    看起来你可能想要这样的东西:

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

    (请参阅Enum类,以及有关其泛型的问题 . )

相关问题