假设我有以下课程:
public class FixExpr {
Expr<FixExpr> in;
}
现在我想介绍一个泛型参数,抽象使用Expr:
public class Fix<F> {
F<Fix<F>> in;
}
但Eclipse并不喜欢这样:
F型不是通用的;它不能使用参数&lt; Fix&lt; F&gt;&gt;
进行参数化
这是可能的还是我忽略了导致这个特定实例破坏的东西?
一些背景信息:在Haskell中,这是编写泛型函数的常用方法;我正在尝试将其移植到Java。上例中的类型参数F具有种类* - &gt; *而不是通常的种类*。在Haskell中它看起来像这样:
newtype Fix f = In { out :: f (Fix f) }
答案 0 :(得分:25)
也许您可以尝试Scala,它是一种在JVM上运行的函数式语言,支持更高级的泛型。
[编辑Rahul G]
以下是您的特定示例粗略转换为Scala的方式:
trait Expr[+A]
trait FixExpr {
val in: Expr[FixExpr]
}
trait Fix[F[_]] {
val in: F[Fix[F]]
}
答案 1 :(得分:24)
我认为您尝试做的事情根本不受Java泛型支持。更简单的
案例public class Foo<T> {
public T<String> bar() { return null; }
}
也不能使用javac进行编译。
由于Java在编译时不知道T
是什么,因此无法保证T<String>
完全有意义。例如,如果您创建了Foo<BufferedImage>
,则bar
会有签名
public BufferedImage<String> bar()
这是荒谬的。由于没有机制强制您仅使用泛型Foo
实例化T
,因此它拒绝编译。
答案 2 :(得分:5)
为了传递一个类型参数,类型定义必须声明它接受一个(它必须是泛型)。显然,您的F
不是通用类型。
更新:行
F<Fix<F>> in;
声明一个类型F
的变量,它接受一个类型参数,其值为Fix
,它本身接受一个类型参数,其值为F
。您的示例中甚至没有定义F
。我认为你可能希望
Fix<F> in;
这将为您提供一个类型Fix
的变量(您在示例中定义的类型),您将向其传递值为F
的类型参数。由于Fix
被定义为接受类型参数,因此可以使用。
更新2:重新阅读您的标题,现在我认为您可能正尝试执行与"Towards Equal Rights for Higher-Kinded Types"中提供的方法类似的操作(PDF警报)。如果是这样,Java不支持,但您可以尝试Scala。
答案 3 :(得分:1)
但是,有一些方法可以用Java编码高质量的泛型。请看higher-kinded-java project。
将此作为库使用,您可以像这样修改代码:
public class Fix<F extends Type.Constructor> {
Type.App<F, Fix<F>> in;
}
您可能应该在@GenerateTypeConstructor
类
Expr
注释
@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);
}
}
}
答案 4 :(得分:1)
正如 Victor 所指出的,有一种迂回的方式在 Java 中编码更高级的类型。它的要点是引入一个类型 <!--Bottom Section-->
<section class="row">
<!--First Row-->
<!--Card One-->
<div class="col-lg-3">
<div class="card">
<img class="img-fluid" src="https://placebear.com/225/225"/>
<p class="card-body">These bears are playing around</p>
<button class="card-body bg-primary p-lg-2 m-2 rounded text-light">See more bears</button>
</div>
</div>
<!--Card Two-->
<div class="col-lg-3">
<div class="card">
<img class="img-fluid" src="https://placebear.com/225/224"/>
<p class="card-body">This bear is looking off into the distance</p>
<button class="card-body bg-primary p-lg-2 m-2 rounded text-light">See more bears</button>
</div>
</div>
<!--Second Row-->
<!--Card Three-->
<div class="col-lg-3">
<div class="card">
<img class="img-fluid" src="https://placebear.com/225/223"/>
<p class="card-body">This bear just found some food</p>
<button class="card-body bg-primary p-lg-2 m-2 rounded text-light">See more bears</button>
</div>
</div>
<!--Card Four-->
<div class="col-lg-3">
<div class="card">
<img class="img-fluid" src="https://placebear.com/225/222"/>
<p class="card-body">This bear is one of our favorites</p>
<button class="card-body bg-primary p-lg-2 m-2 rounded text-light">See more bears</button>
</div>
</div>
</section>
来编码 H<F, T>
。然后可以使用它来编码函子的不动点(即 Haskell 的 F<T>
类型):
Fix
从这里开始,您可以继续在初始代数上实现变形:
public interface Functor<F, T> {
<R> H<F, R> map(Function<T, R> f);
}
public static record Fix<F extends H<F, T> & Functor<F, T>, T>(F f) {
public Functor<F, Fix<F, T>> unfix() {
return (Functor<F, Fix<F, T>>) f;
}
}
请参阅我的 GitHub repo 以获取工作代码,包括一些示例代数。 (请注意,IDE 就像 IntelliJ 一样,尽管它在 Java 15 上编译和运行都很好),但它在代码方面很挣扎。
答案 5 :(得分:0)
看起来你可能想要这样的东西:
public class Fix<F extends Fix<F>> {
private F in;
}
(参见Enum类,以及有关其泛型的问题。)