为什么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的泛型划分可以做些什么?
答案 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)