I have solved a Y-combinator problem. Just now I found that I cannot reference a generic parameter recursively.
Y = λf.(λx.f (x x)) (λx.f (x x))
for example:
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> {/**/}
Q: How can I use generic parameter on the method g to avoid introducing an additional interface G, and the generic parameter should avoiding the UNCHECKED warnings?
Thanks in advance.
You can declare a generic method with a recursive type definition
<G extends Function<G, IntUnaryOperator>> IntUnaryOperator g(G g) {
return g.apply(g);
}
What doesn’t work, is to invoke this method with a lambda expression, assigning the lambda expression to G. The specification says
15.27.3. Type of a Lambda ExpressionA lambda expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) …
and G is not a functional interface, but a type parameter, and there is no way to infer an actual interface type for G here.
That still works, when you use the actual interface G for the lambda expression:
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> {/**/}
or
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> {/**/}
So the method g is generic with no dependency to the interface G, but the interface is still required to be used as target type for the lambda expression.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With