如何递归引用泛型参数?

hol*_*ava 9 java generics functional-programming java-8

我已经解决了Y-combinator问题.刚才我发现我不能递归地引用泛型参数.

Y = ?f.(?x.f (x x)) (?x.f (x x))
Run Code Online (Sandbox Code Playgroud)

例如:

IntUnaryOperator fact = Y(rec -> n -> n == 0 ? 1 : n * rec.applyAsInt(n - 1));

IntUnaryOperator Y(Function<IntUnaryOperator, IntUnaryOperator> f) {
    return g(g -> f.apply(x -> g.apply(g).applyAsInt(x)));
}

IntUnaryOperator g(G g) {
    return g.apply(g);
}

//        v--- I want to remove the middle-interface `G`
interface G extends Function<G, IntUnaryOperator> {/**/}
Run Code Online (Sandbox Code Playgroud)

:如何在方法上使用泛型参数g以避免引入额外的接口G,并且泛型参数应该避免UNCHECKED警告?

提前致谢.

Hol*_*ger 4

您可以使用递归类型定义来声明泛型方法

\n
<G extends Function<G, IntUnaryOperator>> IntUnaryOperator g(G g) {\n    return g.apply(g);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

xe2x80x99 不起作用的是使用 lambda 表达式调用此方法,并将 lambda 表达式分配给G. 规范

\n
\n15.27.3。Lambda 表达式的类型\n

如果 T 是函数接口类型 (\xc2\xa79.8) \xe2\x80\xa6,则 lambda 表达式在赋值上下文、调用上下文或转换上下文中与目标类型 T 兼容

\n
\n

并且G不是一个函数接口,而是一个类型参数,并且这里无法推断出实际的接口类型G

\n

G当您使用lambda 表达式的实际接口时,这仍然有效:

\n
IntUnaryOperator Y(Function<IntUnaryOperator, IntUnaryOperator> f) {\n    return g((G)g -> f.apply(x -> g.apply(g).applyAsInt(x)));\n}\n\n// renamed the type parameter from G to F to avoid confusion\n<F extends Function<F, IntUnaryOperator>> IntUnaryOperator g(F f) {\n    return f.apply(f);\n}\n\n// can\'t get rid of this interface\ninterface G extends Function<G, IntUnaryOperator> {/**/}\n
Run Code Online (Sandbox Code Playgroud)\n

或者

\n
IntUnaryOperator fact = Y(rec -> n -> n == 0 ? 1 : n * rec.applyAsInt(n - 1));\n\nIntUnaryOperator Y(Function<IntUnaryOperator, IntUnaryOperator> f) {\n    return this.<G>g(g -> f.apply(x -> g.apply(g).applyAsInt(x)));\n}\n\n// renamed the type parameter from G to F to avoid confusion\n<F extends Function<F, IntUnaryOperator>> IntUnaryOperator g(F f) {\n    return f.apply(f);\n}\n\n// can\'t get rid of this interface\ninterface G extends Function<G, IntUnaryOperator> {/**/}\n
Run Code Online (Sandbox Code Playgroud)\n

因此该方法g是通用的,不依赖于接口G,但仍需要将接口用作 lambda 表达式的目标类型。

\n