- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
看着 FSharpPlus我在想如何创建一个通用函数以用于
let qr0 = divRem 7 3
let qr1 = divRem 7I 3I
let qr2 = divRem 7. 3.
let inline divRem (D:^T) (d:^T): ^T * ^T = let q = D / d in q, D - q * d
open System.Runtime.InteropServices
type Default6 = class end
type Default5 = class inherit Default6 end
type Default4 = class inherit Default5 end
type Default3 = class inherit Default4 end
type Default2 = class inherit Default3 end
type Default1 = class inherit Default2 end
type DivRem =
inherit Default1
static member inline DivRem (x:^t when ^t: null and ^t: struct, y:^t, _thisClass:DivRem) = (x, y)
static member inline DivRem (D:'T, d:'T, [<Optional>]_impl:Default1) = let q = D / d in q, D - q * d
static member inline DivRem (D:'T, d:'T, [<Optional>]_impl:DivRem ) =
let mutable r = Unchecked.defaultof<'T>
(^T: (static member DivRem: _ * _ -> _ -> _) (D, d, &r)), r
static member inline Invoke (D:'T) (d:'T) :'T*'T =
let inline call_3 (a:^a, b:^b, c:^c) = ((^a or ^b or ^c) : (static member DivRem: _*_*_ -> _) b, c, a)
let inline call (a:'a, b:'b, c:'c) = call_3 (a, b, c)
call (Unchecked.defaultof<DivRem>, D, d)
let inline divRem (D:'T) (d:'T) :'T*'T = DivRem.Invoke D d
最佳答案
首先我们来看documentation on overloaded methods ,没什么好说的:
Overloaded methods are methods that have identical names in a given type but that have different arguments. In F#, optional arguments are usually used instead of overloaded methods. However, overloaded methods are permitted in the language, provided that the arguments are in tuple form, not curried form.
let f (a : int) (b : string) = printf "%d %s" a b
let f (a : int) (b : int) = printf "%d %d" a b
let g = f 5
g
函数,因为此时它不知道代码中的版本
f
应该叫。所以这段代码将是模棱两可的。
DivRem
中的三个重载静态方法类,它们具有三种不同的类型签名:
static member inline DivRem (x:^t when ^t: null and ^t: struct, y:^t, _thisClass:DivRem)
static member inline DivRem (D:'T, d:'T, [<Optional>]_impl:Default1)
static member inline DivRem (D:'T, d:'T, [<Optional>]_impl:DivRem )
DivRem
的实例,则第二个和第三个似乎无法区分。 ,那么它看起来与第一个重载不明确。此时,将该代码粘贴到 F# Interactive session 会有所帮助,因为 F# Interactive 将生成更具体的类型签名,可以更好地解释它。这是我将该代码粘贴到 F# Interactive 时得到的结果:
type DivRem =
class
inherit Default1
static member
DivRem : x: ^t * y: ^t * _thisClass:DivRem -> ^t * ^t
when ^t : null and ^t : struct
static member
DivRem : D: ^T * d: ^T * _impl:Default1 -> ^a * ^c
when ^T : (static member ( / ) : ^T * ^T -> ^a) and
( ^T or ^b) : (static member ( - ) : ^T * ^b -> ^c) and
( ^a or ^T) : (static member ( * ) : ^a * ^T -> ^b)
static member
DivRem : D: ^T * d: ^T * _impl:DivRem -> 'a * ^T
when ^T : (static member DivRem : ^T * ^T * byref< ^T> -> 'a)
static member
Invoke : D: ^T -> d: ^T -> ^T * ^T
when (DivRem or ^T) : (static member DivRem : ^T * ^T * DivRem -> ^T * ^T)
end
DivRem
这里的实现是最容易理解的;它的类型签名与 FSharpPlus 源代码中定义的类型签名相同。看着
documentation on constraints ,
null
和
struct
约束相反:
null
约束意味着“提供的类型必须支持空文字”(不包括值类型),而
struct
约束意味着“提供的类型必须是 .NET 值类型”。因此,实际上永远无法选择第一个重载;正如古斯塔沃在他出色的回答中指出的那样,它的存在只是为了让编译器能够处理这个类。 (尝试省略第一个重载并调用
divRem 5m 3m
:您会发现它无法编译并显示错误:
The type 'decimal' does not support the operator 'DivRem'
Default1
),第三个重载的参数是派生类 (
DivRem
)。这些方法将始终使用
DivRem
调用实例作为第三个参数,那么为什么会选择第二个方法呢?答案在于第三种方法自动生成的类型签名:
static member
DivRem : D: ^T * d: ^T * _impl:DivRem -> 'a * ^T
when ^T : (static member DivRem : ^T * ^T * byref< ^T> -> 'a)
static member DivRem
这里的参数约束是由以下行生成的:
(^T: (static member DivRem: _ * _ -> _ -> _) (D, d, &r)), r
out
参数。在 C# 中,
DivRem
这里正在寻找的静态方法是一种带参数的方法
(a, b, out c)
. F# 编译器将该签名转换为签名
(a, b) -> c
.所以这个类型约束寻找一个像
BigInteger.DivRem
这样的静态方法。并使用参数
(D, d, &r)
调用它哪里
&r
在 F# 中就像
out r
在 C# 中。该调用的结果是商,并将余数分配给
out
给方法的参数。所以这个重载只是调用
DivRem
所提供类型的静态方法,并返回一个元组
quotient, remainder
.
DivRem
静态方法,那么第二个重载(签名中带有
Default1
的那个)就是最终被调用的那个。这个查找过载
*
,
-
和
/
提供的类型上的运算符并使用它们来计算商和余数。
DivRem
正在使用的类型上的方法,调用它,因为它假定它可以针对该类型进行优化。 q
如 D / d
,然后计算余数为 D - q * d
. divRem
尽可能高效的功能。
关于generics - FSharpPlus divRem - 它是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51129078/
看着 FSharpPlus我在想如何创建一个通用函数以用于 let qr0 = divRem 7 3 let qr1 = divRem 7I 3I let qr2 = divRem 7. 3.
System.Math.DivRem()有什么区别和 %运算符(operator)? 最佳答案 %为您提供除法的余数并完全丢弃商,而 DivRem()计算并返回商和余数。 如果您只关心两个整数相除的余
在我的电脑中,这段代码需要 17 秒(10 亿次): static void Main(string[] args) { var sw = new Stopwatch(); sw.Start()
我是一名优秀的程序员,十分优秀!