如何递归引用泛型参数?

时间:2017-07-26 20:54:49

标签: java generics functional-programming java-8

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

Y = λf.(λx.f (x x)) (λx.f (x x))

例如:

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> {/**/}

:如何在方法g上使用通用参数以避免引入其他接口G,并且通用参数应该避免使用UNCHECKED警告?

提前致谢。

1 个答案:

答案 0 :(得分:4)

您可以使用递归类型定义

声明泛型方法
<G extends Function<G, IntUnaryOperator>> IntUnaryOperator g(G g) {
    return g.apply(g);
}

什么不起作用,是使用lambda表达式调用此方法,将lambda表达式赋给GThe specification

  15.27.3。 Lambda表达式的类型      

如果T是函数接口类型(§9.8),则lambda表达式在赋值上下文,调用上下文或具有目标类型T的转换上下文中是兼容的...

G不是函数接口,而是类型参数,并且无法在此处推断G的实际接口类型。

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

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

// renamed the type parameter from G to F to avoid confusion
<F extends Function<F, IntUnaryOperator>> IntUnaryOperator g(F f) {
    return f.apply(f);
}

// can't get rid of this interface
interface G extends Function<G, IntUnaryOperator> {/**/}

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

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

// renamed the type parameter from G to F to avoid confusion
<F extends Function<F, IntUnaryOperator>> IntUnaryOperator g(F f) {
    return f.apply(f);
}

// can't get rid of this interface
interface G extends Function<G, IntUnaryOperator> {/**/}

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