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