int64不支持LanguagePrimitives.DivideByInt?

时间:2012-03-02 04:11:39

标签: generics f# inline integer-division

为什么int64不支持LanguagePrimitives.DivideByInt?我认为写这样的东西是很自然的:

let inline DivBy2 n = LanguagePrimitives.DivideByInt n 2
let res = DivBy2 100L

但是编译器说int64 doesn't support the operator DivideByInt

我试图欺骗:

type System.Int64 with 
    static member DivideByInt (n: System.Int64) (d: int) = n / (int64 d)

但它不起作用。

通过int执行int64的泛型划分可以做些什么?

5 个答案:

答案 0 :(得分:6)

查看F#源代码,函数DivideByInt中不包含int64类型,我不知道为什么。

您可以定义另一个通用函数:

open LanguagePrimitives
type DivExtension = DivExtension of int with
    static member inline (=>) (x             , DivExtension y) = DivideByInt x y
    static member        (=>) (x:int64       , DivExtension y) = x / (int64 y)
    static member        (=>) (x:DivExtension, DivExtension y) = x

let inline DivByInt x y = x => DivExtension y

或者您甚至可以隐藏原始的DivideByInt函数:

let inline DivideByInt x y = x => DivExtension y

请注意,您还可以添加更多重载(即int),在这种情况下,您不需要最后一次“虚拟”重载来推断正确的签名。

答案 1 :(得分:2)

我收到Don Syme的回复(通过fsbugs电子邮件),当我询问失踪MutliplyByInt并且对DivideByInt的支持有限时:

  唐的答案是:

     

此运算符用于支持“Seq.averageBy”等。这表示总计的伪精确除法。我们没有将机制扩展到超出需要的范围。

所以看起来我误解了这种机制的目的。但我仍然不知道为什么int64不支持DivideByInt,这意味着我们在int64类型的通用操作中受到限制。也许我很困惑,因为当int64不是原始类型时,它看起来像一个原始类型。并且DivideByInt仅针对原始类型定义,这就是为什么不支持它。

答案 2 :(得分:1)

正如您所指出的,DivideByInt主要用于支持Seq.averageBy。不支持整数类型的事实对我来说很有意义,因为[1;2]的平均值应该是1.5,而不是1(这是DivideByInt实现的结果给你)。这会强制您将输入转换为浮点数,从而为您提供预期的答案。

答案 3 :(得分:0)

你能用这种方式定义吗?

let inline DivBy2 n = 
  let one = LanguagePrimitives.GenericOne
  n / (one + one)

答案 4 :(得分:0)

我在这里明显迟到了,但知道你为什么要创建一个divBy2函数会很有趣。这里有两个问题,根据您的需要,解决其中一个问题就足够了。

第一个问题是没有LanguagePrimitives.GenericTwo。这很容易解决,但如果你想为除2以外的除数定义特定的除法函数,那么解决方案的用途有限:

let inline divBy2 n =
    n / (LanguagePrimitives.GenericOne + LanguagePrimitives.GenericOne)

为了减少打字,您可以将LanguagePrimitives.GenericOne指定给变量,随着除数的增加,变量会变得更有用:

let inline divBy4 n =
    let one = LanguagePrimitives.GenericOne
    let two = one + one
    n / (two + two)

如果要创建常规功能,此解决方案也无济于事。 "定制"方式将是

let inline divBy divisor dividend = dividend / divisor

我们可以将它与部分函数应用程序一起用于将字节列表减半,例如,像这样:

let halfBytes = [ 1uy .. 10uy ] |> List.map (divBy 2uy)

但我们可以做得更好。此问题适用于所有非交换运算符,包括减法运算符。为了解决这个问题,我们可以定义

let flip f a b = f b a

这允许,例如

let scaledInThousands = [ 0m .. 500m .. 3000m ] |> List.map (flip (/) 1000m)
let decrementedIntegers = [ 1 .. 10 ] |> List.map (flip (-) 1)

如果需要,您仍然可以定义divBy函数:

let inline divBy n = flip (/) n
let halfInts = [ 1 .. 10 ] |> List.map (divBy 2)
let halfLongs = [ 1L .. 10L ] |> List.map (divBy 2L)
let fifthLongs = [ 1L .. 10L ] |> List.map (divBy 5L)
let oneThroughTenOverPi = [ 1.0 .. 10.0 ] |> List.map (divBy System.Math.PI)