3

为什么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 进行通用除法?

4

5 回答 5

7

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

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

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),在这种情况下,您不需要最后一个“虚拟”重载来推断正确的签名。

于 2012-03-02T06:44:50.277 回答
3

当我询问有关以下方面的缺失MutliplyByInt和有限支持时,我收到了 Don Syme 的答复(通过 fsbugs 电子邮件) DivideByInt

唐的回答:

该运算符的存在是为了支持“Seq.averageBy”等。这表示总数除以计数的伪精确除法。我们没有将机制扩展到超出所需的范围。

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

于 2012-03-08T09:31:54.503 回答
2

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

于 2012-03-08T14:54:54.960 回答
1

你能这样定义吗?

let inline DivBy2 n = 
  let one = LanguagePrimitives.GenericOne
  n / (one + one)
于 2012-03-02T05:35:08.117 回答
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)
于 2014-08-18T20:24:09.920 回答