我创建了以下运算符来帮助安全划分。
let (/!) a b =
if b = 0 then 0
else a / b
问题是它只适用于整数,我希望这个函数适用于任何数字原语(int、float、decimal 等)。
我已经阅读了一些关于自动泛化的文章,但还没有完全深入,我不确定这是否是正确的方向。
我如何完成对这个运算符的泛化?
谢谢,
乔
我创建了以下运算符来帮助安全划分。
let (/!) a b =
if b = 0 then 0
else a / b
问题是它只适用于整数,我希望这个函数适用于任何数字原语(int、float、decimal 等)。
我已经阅读了一些关于自动泛化的文章,但还没有完全深入,我不确定这是否是正确的方向。
我如何完成对这个运算符的泛化?
谢谢,
乔
嗨,这是一个隐藏的宝石,但您正在寻找的是:
let inline (/!) (a : ^a) (b : ^a) : ^a =
if b = LanguagePrimitives.GenericZero
then LanguagePrimitives.GenericZero
else a / b
顺便说一句:这有这个怪物类型:
val inline ( /! ) :
a: ^a -> b: ^a -> ^a
when ^a : equality and ^a : (static member get_Zero : -> ^a) and
^a : (static member ( / ) : ^a * ^a -> ^a)
(这就是为什么我真的不喜欢在声明中写这个;))
正如您所看到的,它支持通用数字代码,但并不经常讨论(F# 有一些类型类,比如内置的东西 - 这是一个例子,其他的是类似的东西comparable
,等等)
Tomas 写了一篇很好的文章:Writing generic numeric code
PS你也不需要^a
- 但我有点喜欢写签名 - 即使你可以这样做:
let inline (/!) a b =
if b = LanguagePrimitives.GenericZero
then LanguagePrimitives.GenericZero
else a / b
val inline ( /! ) :
a: ^a -> b: ^b -> ^c
when ( ^a or ^b) : (static member ( / ) : ^a * ^b -> ^c) and
^b : (static member get_Zero : -> ^b) and ^b : equality and
^c : (static member get_Zero : -> ^c)
这对你没有好处,因为真正的除法运算符通常只针对两个参数的一种类型 - 正如我所说:我喜欢强调参数名称的类型;)
你可以绕过这样的GenericZero
事情:
> let inline (/!) a b = if b = (b-b) then (b-b) else a/b;;
val inline ( /! ) :
a: ^a -> b: ^b -> ^b
when ( ^a or ^b) : (static member ( / ) : ^a * ^b -> ^b) and
^b : (static member ( - ) : ^b * ^b -> ^b) and ^b : equality
(为了安全起见:您可能会在此处遇到某些类型/数字的问题;))