2017-07-26 59 views
9

我已經解決了一個Y組合問題。剛纔我發現我不能遞歸地引用泛型參數。如何遞歸引用泛型參數?

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

Q:如何使用在方法g通用參數,以避免引入附加的接口G,和通用參數應避免UNCHECKED警告?

在此先感謝。

+2

我很確定這是不可能的。 Java沒有提供一種方法來要求給定的泛型參數是一個功能接口AFAIK。 – Ryan

回答

4

你可以聲明泛型方法與遞歸類型定義

<G extends Function<G, IntUnaryOperator>> IntUnaryOperator g(G g) { 
    return g.apply(g); 
} 

什麼也不行,是調用此方法lambda表達式,分配lambda表達式GThe specification

15.27.3。一個Lambda表達式的類型

lambda表達式是在分配上下文,調用上下文,或與目標類型T鑄造上下文兼容如果T是一個功能接口類型(§9.8)...

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表達式的目標類型。

+0

是的,我剛剛發現類型變量也可以遞歸引用。並且問題發生在lambda表達式中。非常感謝先生。例如'g(null)'可以正常工作,但'g(g - > null)'不能工作。 –