我仍然试图围绕F#如何概括(或不是)函数和类型,并且有一个案例让我烦恼:
let min(a, b) = if a < b then a else b
let add(a, b) = a + b
let minInt = min(3, 4)
let minFloat = min(3.0, 4.0) // works!
let addInt = add(3, 5)
let addFloat = add(3.0, 5.0) // error: This expression was expected to have type
// int but here has type float
Run Code Online (Sandbox Code Playgroud)
这里min具有泛型类型,'a * 'a -> 'a (requires comparison)而add具有一种具体类型int * int -> int,显然是从它在程序中的第一次使用推断出来的.两者都以相同的方式声明和使用,那为什么泛化的区别呢?
我理解在add的情况下,问题可以通过声明函数内联来进行,因为它会导致它获得泛型类型定义,即'a * 'b -> 'c (requires …
我最近遇到了来自F#编译器的一些意外行为.我能够找到一种解决方法,但最初的行为令我感到困惑,我想看看是否有人可以帮助我理解是什么导致它.
我定义为非泛型的函数变得通用,这干扰了函数在多个调用之间共享状态的能力.我将用例简化为以下内容:
let nextId =
let mutable i = 0
let help (key:obj) =
i <- i + 1
i
help
nextId "a" // returns 1
nextId "b" // also returns 1!!!!
Run Code Online (Sandbox Code Playgroud)
为什么nextId类型为'a - > int而不是obj - > int?显然,泛化也是导致其反复返回1的错误的原因,但为什么泛化首先发生呢?
请注意,如果我在没有命名嵌套函数的情况下定义它,它会在给出唯一ID时按预期工作:
let nextId =
let mutable i = 0
fun (key:obj) ->
i <- i + 1
i
nextId "a" // returns 1
nextId "b" // returns 2
Run Code Online (Sandbox Code Playgroud)
但更神秘的是,根据这个定义,F#Interactive无法决定nextId是(obj - > int)还是('a - > int).当我第一次定义它时,我得到了
val nextId:(obj - > …
我最近遇到了一个意想不到的代码优化,并想检查我对我观察的内容的解释是否正确.以下是一个简化的情况示例:
let demo =
let swap fst snd i =
if i = fst then snd else
if i = snd then fst else
i
[ for i in 1 .. 10000 -> swap 1 i i ]
let demo2 =
let swap (fst: int) snd i =
if i = fst then snd else
if i = snd then fst else
i
[ for i in 1 .. 10000 -> swap 1 i i ]
Run Code Online (Sandbox Code Playgroud)
2个代码块之间的唯一区别是在第二种情况下,我明确地将swap的参数声明为整数.然而,当我用#time在fsi中运行2个片段时,我得到:
情况1实时:00:00:00.011,CPU:00:00:00.000,GC gen0:0,gen1:0,gen2:0
情况2实时:00:00:00.004,CPU:00:00:00.015,GC …
当运算符的一侧具有已知类型而另一侧不具有已知类型时,某些函数用法不会编译.一个例子是计量单位:
let inline multiplyWithFive x = 5. * x
type [<Measure>] myUnit
let test = multiplyWithFive 3.<myUnit> // Compiler error
Run Code Online (Sandbox Code Playgroud)
5. * 3.<myUnit>显然是一个有效的表达式,所以这是令人惊讶的,特别是考虑到inline函数在其他情况下最大化:
let inline multiply a b = a * b
let test = multiply 5. 3.<myUnit> // Valid
Run Code Online (Sandbox Code Playgroud)
但是,这不仅限于计量单位.比方说,我做了一个支持浮点数不对称乘法的类型.它与multiplyWithFive函数不兼容,函数任意推断其参数为float:
type BoxFloat =
{ Value : float }
static member inline (*) (lhs : float, rhs : BoxFloat) =
{ Value = lhs * rhs.Value }
let boxThree = { Value = …Run Code Online (Sandbox Code Playgroud) 我创建了以下运算符来帮助安全划分.
let (/!) a b =
if b = 0 then 0
else a / b
Run Code Online (Sandbox Code Playgroud)
问题是它只适用于整数,我希望这个函数可以处理任何数字原语(int,float,decimal等).
我已经完成了关于自动泛化的一些阅读,但它并没有完全沉入,而且我不确定这是否是正确的方向.
如何完成此运算符的推广?
谢谢,
乔