2010-03-15 36 views
3

下面的代碼在「評估」失敗:
「這個表達,預計將有類型複雜,但這裏的類型爲雙榜」
我是不是打破關於運算符在「(+)」上加載的一些規則?
如果我將'(+)'更改爲'添加',情況還可以。F#操作過載:(+),爲用戶defind型

open Microsoft.FSharp.Math 

/// real power series [kn; ...; k0] => kn*S^n + ... + k0*S^0 
type Powers = double List 

let (+) (ls:Powers) (rs:Powers) = 
    let rec AddReversed (ls:Powers) (rs:Powers) = 
     match (ls, rs) with 
     | (l::ltail, r::rtail) -> (l + r) :: AddReversed ltail rtail 
     | ([], _) -> rs 
     | (_, []) -> ls 
    (AddReversed (ls |> List.rev) (rs |> List.rev)) |> List.rev 

let Evaluate (ks:Powers) (value:Complex) = 
    ks |> List.fold (fun (acc:Complex) (k:double)-> acc * value + Complex.Create(k, 0.0) ) Complex.Zero 

回答

9

與您的代碼的問題是,你的+定義實際上隱藏了運營商的所有以前的定義,所以F#編譯器認爲+只能爲另外Powers值的使用。這是因爲包含F#運算符的函數值(使用let聲明)不支持重載。

但是,如果您將它們添加爲某種類型的static member,則可以重載F#運算符。這對abberviations不起作用,因此您需要首先將類型聲明更改爲記錄或區分聯合(我選擇第二個選項)。然後你就可以實現重載操作是這樣的:

/// real power series [kn; ...; k0] => kn*S^n + ... + k0*S^0 
type Powers = 
    | P of double list 
    static member (+) (P ls, P rs) = 
    let rec AddReversed ls rs = 
     match (ls, rs) with 
     | (l::ltail, r::rtail) -> (l + r) :: AddReversed ltail rtail 
     | ([], _) -> rs 
     | (_, []) -> ls 
    P ((AddReversed (ls |> List.rev) (rs |> List.rev)) |> List.rev) 

注意,運營商現在正在申報爲Powers類型的一部分。由於該類型是一個有區別的聯合,我需要添加展開參數(P ls, P rs),然後重新包裝結果。你Evaluate功能看起來就像這樣:

let Evaluate (P ks) (value:Complex) = 
    ks |> List.fold (fun (acc:Complex) (k:double)-> 
    acc * value + Complex.Create(k, 0.0) ) Complex.Zero 

它需要再次解開值(P ks),但其餘代碼不變。

+0

不應該用'static member(+)...'讀取''? – 2012-05-01 11:29:01

+0

'with'關鍵字是可選的。我更喜歡不使用它的簡單語法,但它可以在那裏。 – 2012-05-01 13:45:22