2010-12-02 50 views
3

我試圖寫:如何聲明一個返回滿足F#中多個約束的類型的泛型函數?

type A() = 
    interface IX with ... 
    interface IY with ... 

type B() = 
    interface IX with ... 
    interface IY with ... 

let mk t : 'T when 'T :> IX and 'T :> IY = 
    match t with 
    | Choice1 -> new A() 
    | Choice2 -> new B() 

注意對MK的返回類型的類型約束。它不編譯,但編譯器抱怨說它不能將A和B轉換成'T.

+1

只是爲了好玩,比較C#http://pastebin.com/daFFKTwB中的等效代碼。你試圖返回一個具體類型的'T,但是你不會在你的函數的其他部分使用這種類型 - 你試圖返回一個具體的A或B,而類型檢查器不能找出什麼你真的打算。 – Juliet 2010-12-02 19:50:36

+0

需要考慮的更多:如果我寫`let x,y = mk Choice1,mk Choice2`,`x`和`y`有什麼類型? – Juliet 2010-12-02 20:46:55

回答

7

約束沒問題,但問題是沒有滿足約束條件的類型,並且這兩個類型都是AB的超類型。

match構造需要從兩個分支返回相同的類型,所以您需要將upcast(:>)添加到某種類型,以便轉換對兩個分支都起作用。該類型可能是IXIY,但這不會滿足約束條件。

這隻有在.NET允許你寫類似IX+IY這意味着實現兩個接口的類型時纔可能。然後,你也可以使用這種類型的例如爲:

let (a:IX+IY) = new A() // This isn't supported 

我認爲,最好的解決辦法是隻返回一個元組包含相同的實例兩次IX * IY值的工作,但表示爲不同的類型。在這裏,你寫的constriant是非常有用的:

// Type: 'a -> IX * IY when 'a :> IX and 'a :> IY 
let asTuple a = (a :> IX, a :> IY) 

let mk t = 
    match t with 
    | Choice1Of2() -> new A() |> asTuple 
    | Choice2Of2() -> new B() |> asTuple 
7

如果你控制類型AB,那麼最簡單的解決辦法是定義

type IXY = 
    inherit IX 
    inherit IY 

,然後有AB繼承IXY,和mk只會返回一個IXY而不是一個泛型(即使沒有約束,它也沒有意義)。

相關問題