要一些解釋添加到發佈的ChaosPandion,與F#功能該問題的代碼一樣abs
的是,他們可以與任何數值類型的工作。沒有辦法用F#/ .NET泛型來表達它 - 唯一支持的約束是該類型參數實現了某個接口或者具有構造函數,但是對於數字類型沒有限制。因此,F#還支持靜態約束(類型參數是^a
,而不是通常的'a
),並且這些在編譯時使用內聯進行處理(這也解釋了爲什麼該函數必須是inline
)。您可以通過使用內置函數從LanguagePrimitives
它包含需要一些限制許多有用的功能給你寫靜態約束自己的功能:
> let inline half (num: ^a) : ^a =
LanguagePrimitives.DivideByInt< (^a) > num 2
;;
val inline half : ^a -> ^a
when ^a : (static member DivideByInt : ^a * int -> ^a)
> half 42.0;;
val it : float = 21.0
> half 42.0f;;
val it : float32 = 21.0f
注意約束推斷 - DivideByInt
要求類型有DivideByInt
成員,所以我們的功能需要相同的東西(如果它也有這個成員,它會和你自己的類型一起工作,這非常有用!)。
除此之外,的abs
的實現使用的是隻允許在F#庫兩個額外的花樣 - 它指定不同的代碼(以內聯時,可以使用),用於不同類型的(使用when ^a:int = ....
)和回退的情況下,這使用Abs
成員,因此它可以與任何明確列出的類型或與Abs
成員的類型一起使用。另一個訣竅是retype
函數「更改類型」,但不包含任何代碼 - 唯一的目的是進行代碼類型檢查,但這可能非常不安全 - 因此僅在F#庫中使用。
您不必將X與0進行比較以找到其絕對值 - 您可以將其與-X進行比較。 – Simon 2010-02-03 15:04:11
@西蒙看起來不錯。但是,你的方法不正確。考慮x = -2147483648。 – 2010-02-03 15:17:22
是的,好點 - 雖然我懷疑你會得到相同的異常,試圖評估-X在這種情況下,因爲abs()應該拋出。 – Simon 2010-02-03 15:56:27