有一个泛型函数LanguagePrimitives.DivideByInt
除以int
而不会丢失泛型行为,我们可以像这样使用它:
let inline Divideby2 n = LanguagePrimitives.DivideByInt n 2
val inline Divideby2 :
^a -> ^a when ^a : (static member DivideByInt : ^a * int -> ^a)
但是没有名为MultiplyByInt
的函数来执行int
的通用乘法。有没有什么可以执行泛型乘法?像这样:
let inline MultiplyBy2 n = SomeGenericFunctionsModule.MultiplybyInt n 2;
P.S。我们总是可以使用一些非标准的方法,如:
let inline MultiplyByInt n m = seq { for i in 1..m -> n} |> Seq.sum
但我很感兴趣是否有可能以正确的方式进行。
答案 0 :(得分:5)
我担心没有内置功能,但我可以提出两种替代解决方案:
type MulExtension = MulExtension of int with
static member (=>) (x:float , MulExtension y) = x * (float y)
static member (=>) (x:decimal, MulExtension y) = x * (decimal y)
static member (=>) (x:int64 , MulExtension y) = x * (int64 y)
// More overloads
let inline MultiplyByInt x y = x => MulExtension y
但是你必须指定每种类型。 我宁愿使用这个功能:
let inline MultiplyByInt x y =
let fromInt (n:int) : ^a when ^a : (static member (*) : ^a * ^a -> ^a) =
System.Convert.ChangeType(n, typeof<'a>) :?> 'a
x * (fromInt y)
我看不出两种方法之间在性能上有任何差异。
答案 1 :(得分:2)
我设法在O(log(N))
获得了一个击败你的解决方案,但它仍然感觉非常难看
let inline MulInt (m:^t) (n:int) =
let r : ^t ref = ref LanguagePrimitives.GenericZero
let addv : ^t ref= ref LanguagePrimitives.GenericOne
while ((int) !r) < n do
if int(!r + !addv + !addv) < n then
addv := !addv + !addv
else
r := !r + !addv
addv := LanguagePrimitives.GenericOne
!r * m
使用某些库中的某些功能可以使这更好一些,但会导致警告。
注意:此解决方案假定n
中可以表示^t
- 即
MulInt 2uy 5000
将永远循环
答案 2 :(得分:1)
let inline MultiplyByInt n (x: ^a) =
let zero : ^a = LanguagePrimitives.GenericZero
let one : ^a = LanguagePrimitives.GenericOne
if n = 0 then zero
else
let mutable q, r = System.Math.DivRem(abs n, 2)
let mutable y = x
while q > 0 do
y <- y + y
q <- q / 2
let y = if r = 0 then y else y + x
if n > 0 then y
else y * (zero - one)
答案 3 :(得分:1)
我收到Don Syme的回复(通过fsbugs电子邮件),当我询问失踪MutliplyByInt
并且对DivideByInt
的支持有限时:
唐的答案是:此运算符用于支持“Seq.averageBy”等。这表示总计的伪精确除法。我们没有将机制扩展到超出需要的范围。
所以看起来我误解了这种机制的目的。