2013-03-26 116 views
3

我在F#試圖創建一個通用的接口,它的類型參數必須支持另外,讓我結束了這樣的事情:通用接口,其中類型參數支持另外

type IMyInterface<'b when 'b : (static member (+) : 'b * 'b -> 'b)> = 
    abstract member myFunction : 'b -> 'b 

不幸的是這片代碼給我下面的錯誤:

This code is not sufficiently generic. The type variable ^D when ^D : comparison and ^D : (static member (+) : ^D * ^D -> ^D) could not be generalized because it would escape its scope.

我發現this question對於同樣的問題,但我不知道我的理解爲什麼功能已被標記爲inline

而且,因爲你不能讓一個抽象的成員inline,也存在另一種解決方案,我可以在我的具體的例子使用?還是我必須找到一個完整的方法來實現這個目標?

回答

7

首先,我想我不完全理解爲什麼你需要說明接口的類型參數支持加法 - 我想在實現MyFunction時會使用加法,在這種情況下,接口的調用者不需要知道它。如果你要揭露此外,你可以簡單地將其添加爲一個單獨的方法:

type IMyInterface<'T> = 
    abstract Add : 'T * 'T -> 'T 
    abstract MyFunction : 'T -> 'T 

我覺得靜態成員約束並不在其他地方比inline功能或inline靜態成員的工作非常好(但我可能是錯誤)。如果你需要使用一個通用型內數字操作,您可以使用一個技巧,捕捉在接口的實現(在inline法),並將它們存儲。在我的blog about generic math in F#的末尾有一個這樣的例子。

的竅門是定義一個接口與你需要的數字運算,並把它作爲一個額外的參數的構造器:

type IAddition<'T> = 
    abstract Add : 'T * 'T -> 'T 

type MyType<'T>(a:'T, b:'T, add:IAddition<'T>) = 
    member x.Sum = add.Add(a, b) 

到目前爲止,這是一個標準的.NET方式使用接口 - 該接口表示數字操作,我們通過接口調用它們。現在,關鍵是要增加inline方法Create即只需兩個參數,需要+爲靜態約束。然後,該方法可以實現該接口,並把它傳遞給MyType作爲最後一個參數:

static member inline Create(a:^N, b:^N) = 
    let ops = 
     { new IAddition<^N> with 
      member x.Add(a, b) = a + b } 
    MyType<^N>(a, b, ops) 

現在你可以寫MyType<_>.Create(1, 2)和整數+操作將在一個界面中自動捕捉和存儲(這是比較容易在你的其他代碼中工作)。

2

Statically Resolved Type Parameters MSDN上可以澄清inline的需要。底線是你不能把約束放在界面上,也不是它所需要的。 (?難道你真的想要一個接口「泄漏」數額是多少,一個實現細節請記住,這個約束只存在在編譯時。)功能可以inline,所以此工程:

type IMyInterface<'b> = 
    abstract member myFunction : 'b -> 'b 

// (^b : (static member (+) ...) constraint is inferred 
let inline makeMyInterface() = 
    { new IMyInterface<_> with 
     member x.myFunction b = b + b } 
相關問題