2012-09-24 42 views
4

因此,在做一些Project Euler問題時,我希望能夠取整數值(int,long,bigint等)的平方根,但Sqrt僅爲浮點值定義。所以我一直在寫我自己的小牛頓 - 拉夫森算法,它對我所需要的很精確。不過,我希望能夠在浮點值上調用內置的sqrt函數。所以我寫了這樣的事情:F#過度進取型推斷?

let inline dsqrt x = 
    match box x with 
    | :? float -> sqrt x 
    | :? float32 -> sqrt x 
    | _ -> p_dsqrt x 

我的功能,很顯然,被命名爲 「p_dsqrt」。然而,這個函數要求輸入定義了一個Sqrt方法,這種方式會失敗整個目的。我是否缺少某種類型的約束,或者是什麼?

+0

如果它是有用的,下面是我在歐拉問題中用於整數平方根的代碼:http://fssnip.net/dR – ildjarn

+0

什麼是預期的返回類型? –

回答

3

我想你也許想這樣,而是:

let dsqrt x = 
    match box x with 
    | :? float as f -> sqrt f |> box :?> 'a 
    | :? float32 as f -> sqrt f |> box :?> 'a 
    | _ -> p_dsqrt x 

與您的代碼的問題是,你直接調用sqrt x,這限制了可能的類型x。在我的修改後的代碼中,我將一個新的標識符綁定到成功強制的結果floatfloat32,所以這不會對x的類型施加任何限制。

+1

雖然'dsqrt'仍然是'inline',但要正確地將'x'的類型傳播到'p_dsqrt'? – ildjarn

+0

不幸的是,我現在剛剛得到一個不同的錯誤。我得到「類型'float'與'float32'類型不匹配」。當我刪除'float32'的情況下,該功能仍然解決爲「浮動 - >浮動」。作爲參考,我的p_dsqrt函數解析爲「'a - >'a」。 –

+0

@LeeCrabtree - 對不起,我更新了我的答案。還需要動態轉換回泛型類型。 – kvb

6

如果你想使用的匹配,不需要inline關鍵字,但如果你想使用的內聯函數和「帽子類型」,超載使用,而不是比賽:

type Sqrt = Sqrt with 
    // Dummy overload in order to get the right types inferred (will never reach here) 
    static member inline ($) (Sqrt, _:^t when ^t:null and ^t: struct) = id 

    // Existing sqrt 
    static member inline ($) (Sqrt, x:'a) :'a = sqrt x 

    // Your Newton-Raphson based sqrt's 
    static member  ($) (Sqrt, x:int ) = sqrtForInt x 
    static member  ($) (Sqrt, x:bigint) = sqrtForBigInt x 

let inline sqrt (x:'t) :'t = Sqrt $ x 

則返回類型始終與輸入類型相同,所選sqrt的實現取決於該類型。這個選擇將在編譯時發生,這是與在運行時解決的匹配方法的主要區別。

如果我拿出虛擬過載,它將和你的代碼有同樣的問題:它需要sqrt約束。

+0

哇,這只是輝煌:) –

+0

這是如何工作的?我無法理解我在讀什麼!結果令人印象深刻。 – Joh