2012-10-19 73 views
3

我試圖定義一個重載的運算符,例如|+|,如下:F#中重載的內聯運算符:(| + |)

let inline (|+|) (m1 : #IMeasurable) (m2 : #IMeasurable) = m1.Measure + m2.Measure 

的問題是,我不能這樣做:由於運營商|+|的情況下(m1 : int) (m2 : #IMeasurable)沒有定義

let three = m1 |+| m2 |+| m3 

。有沒有辦法重載這個操作符或使用靜態類型約束來使上述表達式成爲可能?有沒有辦法修改IMeasurable(我可以編輯),以便這是可能的?還有什麼可以讓上述表達式起作用的東西?

謝謝。

回答

11
type Overloads = Overloads with 
    static member ($) (Overloads, m1: #IMeasurable) = fun (m2: #IMeasurable) -> m1.Measure + m2.Measure 
    static member ($) (Overloads, m1: int) = fun (m2: #IMeasurable) -> m1 + m2.Measure 

let inline (|+|) m1 m2 = (Overloads $ m1) m2 

未測試,因爲我沒有IMeasurable,但它可能會完成這項工作。

5

如果你定義一個運算符的行爲像+那麼我認爲最好的設計是定義一個運算符,返回與它的參數類型相同的值。這意味着,我會改變運營商返回IMeasurable而不是int

type IMeasurable = 
    abstract Measure : int 

let newMeasure m = 
    { new IMeasurable with 
     member x.Measure = m } 

let inline (|+|) (m1 : #IMeasurable) (m2 : #IMeasurable) = 
    newMeasure (m1.Measure + m2.Measure) 

這將使運營商定義,更均勻,更容易使用。該代碼你想寫將現在的工作(返回IMeasurable),但你也可以使用Seq.reduce

// Now you can add multiple measure values without issues 
let res = (newMeasure 2) |+| (newMeasure 3) |+| (newMeasure 4) 

// Moreover, you can also use `Seq.reduce` which would not work 
// with your original operator (because it has wrong type) 
let res = [newMeasure 2; newMeasure 3; newMeasure 4] |> Seq.reduce (|+|) 

這就是說,如果你真的想重載正在使用let限定的操作,你可以把它添加到一類是靜態成員(因爲你不能修改的型),那麼你就需要使用技巧,古斯塔沃介紹

+0

返回一個'IMeasurable'沒有意義在這種情況下,我害怕。 – GregRos

+0

嗯,如果返回'IMeasurabe'沒有邏輯意義,那麼你可能需要遵循@Gustavo的建議。雖然也許這意味着,具有簡單的函數,'IMeasurable'轉換爲'int',然後使用標準的'+'爲'int's將是一個很好的選擇。運營商定製是相當困難的,而發現像'm1.Measure + m2.Measure + m3.Measure'是不是太長,容易編寫和理解。 –