Java中更高级的泛型

假设我有以下课程:

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)

2 years ago

我认为你想要做的就是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 ,因此它拒绝编译 .

2 years ago

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


[ EDIT by Rahul G ]

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

trait Expr[+A]

trait FixExpr {
  val in: Expr[FixExpr]
}

trait Fix[F[_]] {
  val in: F[Fix[F]]
}

2 years ago

为了传递一个类型参数,类型定义必须声明它接受一个(它必须是通用的) . 显然,您的 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 .

2 years ago

仍然有一些方法可以用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);
        }
    }

}

2 years ago

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

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

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