标签: automatic-generalization

F#中的通用函数

我仍然试图围绕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 …

generics f# automatic-generalization

9
推荐指数
1
解决办法
1449
查看次数

为什么F#编译器有时会错误地推广函数?

我最近遇到了来自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 - > …

generics f# automatic-generalization

9
推荐指数
2
解决办法
181
查看次数

F#自动泛化和性能

我最近遇到了一个意想不到的代码优化,并想检查我对我观察的内容的解释是否正确.以下是一个简化的情况示例:

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 …

optimization f# automatic-generalization

7
推荐指数
1
解决办法
262
查看次数

为什么自动泛化有时会推断过度特定的类型?

当运算符的一侧具有已知类型而另一侧不具有已知类型时,某些函数用法不会编译.一个例子是计量单位:

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)

generics f# inline automatic-generalization

4
推荐指数
1
解决办法
78
查看次数

如何在一个简单的函数中实现自动泛化

我创建了以下运算符来帮助安全划分.

let (/!) a b = 
    if b = 0 then 0 
    else a / b
Run Code Online (Sandbox Code Playgroud)

问题是它只适用于整数,我希望这个函数可以处理任何数字原语(int,float,decimal等).

我已经完成了关于自动泛化的一些阅读,但它并没有完全沉入,而且我不确定这是否是正确的方向.

如何完成此运算符的推广?

谢谢,

f# automatic-generalization

3
推荐指数
1
解决办法
108
查看次数