2013-01-01 87 views
3

是否可以爲F#元組編寫擴展方法?例如,添加實例方法.Item1和.Item2(如System.Tuple)相當於爲2元組調用fst和snd?F#元組的擴展方法

回答

1

不完美,但我用這個。 (我從http://www.fssnip.net/6V借原代碼,增加了小的修改。)

[<AutoOpen>] 
module TupleExtensions = 
    type System.Tuple with 
    static member Item1(t) = let (x,_) = t in x 
    static member Item1(t) = let (x,_,_) = t in x 
    static member Item1(t) = let (x,_,_,_) = t in x 
    static member Item1(t) = let (x,_,_,_,_) = t in x 
    static member Item1(t) = let (x,_,_,_,_,_) = t in x 
    static member Item1(t) = let (x,_,_,_,_,_,_) = t in x 

    static member Item2(t) = let (_,x) = t in x 
    static member Item2(t) = let (_,x,_) = t in x 
    static member Item2(t) = let (_,x,_,_) = t in x 
    static member Item2(t) = let (_,x,_,_,_) = t in x 
    static member Item2(t) = let (_,x,_,_,_,_) = t in x 
    static member Item2(t) = let (_,x,_,_,_,_,_) = t in x 

    static member Item3(t) = let (_,_,x) = t in x 
    static member Item3(t) = let (_,_,x,_) = t in x 
    static member Item3(t) = let (_,_,x,_,_) = t in x 
    static member Item3(t) = let (_,_,x,_,_,_) = t in x 
    static member Item3(t) = let (_,_,x,_,_,_,_) = t in x 

    static member Item4(t) = let (_,_,_,x) = t in x 
    static member Item4(t) = let (_,_,_,x,_) = t in x 
    static member Item4(t) = let (_,_,_,x,_,_) = t in x 
    static member Item4(t) = let (_,_,_,x,_,_,_) = t in x 

    static member Item5(t) = let (_,_,_,_,x) = t in x 
    static member Item5(t) = let (_,_,_,_,x,_) = t in x 
    static member Item5(t) = let (_,_,_,_,x,_,_) = t in x 

    static member Item6(t) = let (_,_,_,_,_,x) = t in x 
    static member Item6(t) = let (_,_,_,_,_,x,_) = t in x 

    static member Item7(t) = let (_,_,_,_,_,_,x) = t in x 

如何使用它:

let t = (1, 2, 3) 
let item1 = Tuple.Item1(t) 

Tuple.Item1這裏定義有超過FST的優勢:它是多態的項目數。一旦我們使用這些擴展方法編寫使用n元組的函數,我們可以在不修改函數體的情況下將其擴展爲n + 1元組。相反,我們必須修改參數類型聲明。這是更輕鬆。

5

在F#中內部表示(2元素)元組的System.Tuple<'T1, 'T2>類型實際上已經具有屬性Item1Item2,但它們被F#編譯器隱藏。向元組添加擴展成員的一個顯而易見的方法並不能解決問題,所以我不希望這樣做(但可能有一些我不知道的解決方法)。

一般來說,我認爲模式匹配比諸如Item1,Item2等成員更可取(並且C#3.0程序員在處理元組時通常要求模式匹配支持:-))。

原因是模式匹配強制你命名的東西。比較這兩個代碼段:

let (width, height) = tuple 
width * height 

和使用性能的版本:

tuple.Item1 * tuple.Item2 

第二個是一個位短,但絕對少可讀。

+0

感謝Tomas。我同意,但是如果有解決方法,我仍然對此感興趣(而不是像下面的bytebuster建議的那樣採用新的類型)? – mpeac

0

我想,你所要求的不是很有功能的方式。您可以使用實例方法創建自己的類型,但同時您正在失去函數式編程的許多方面,例如模式匹配。

除此之外,一個DU似乎是要走的路:

type MyTuple<'T, 'U> = 
    | MyTuple of 'T * 'U 
    with 
    member this.MyItem1 = match this with | MyTuple(x,y) -> x 
    member this.MyItem2 = match this with | MyTuple(x,y) -> y 

let x = MyTuple(42, "foo") 
let y1 = x.MyItem1 // 42 
let y2 = x.MyItem2 // "foo" 

由於@Tomas Petricek指出,因爲他們在System.Tuple<'T1, 'T2>已經存在,所以無法命名的屬性Item1Item2。試圖這樣做將導致一個錯誤:

error FS2014: A problem occurred writing the binary [filename]: Error in pass2 for type [...], error: Error in pass2 for type MyTuple`2, error: duplicate entry 'Item1' in property table

0

您也可以使用fstsnd功能得到你想要的值(顯然寫自己的第三,第四,等等。如果你真的想) 。

0

解決方法是使用C#樣式擴展定義。

這會工作得很好:

open System.Runtime.CompilerServices 

[<Extension>] 
type TupleExtensions() = 
    [<Extension>] static member First((a,b)) = a 
    [<Extension>] static member First((a,b,c)) = a 

let x = (1,2).First() 
let y = (1,2,3).First() 

但我同意,這不是一個好主意,通過方法來訪問一個元組的元素,模式匹配是最好的方式。