Max*_*son 9 generics f# automatic-generalization
我最近遇到了来自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 - > int)
但如果我只是评估
nextId
Run Code Online (Sandbox Code Playgroud)
我明白了
val it:('a - > int)
这里发生了什么,为什么我的简单函数会自动推广?
我同意这是非常意外的行为.我认为F#执行泛化的原因是它将help(当返回时)视为fun x -> help x.调用一个函数obj似乎是编译器执行泛化的一种情况(因为它知道任何东西都可以obj).例如,在以下情况下会发生相同的概括:
let foo (o:obj) = 1
let g = fun z -> foo z
Run Code Online (Sandbox Code Playgroud)
在这里,g变得'a -> int太,就像在你的第一个版本.我不太清楚为什么编译器会这样做,但你看到的可以通过1)处理helpas fun x -> help x和2)推广调用来解释obj.
另一件事是F#如何处理泛型值 - 泛型值在ML语言中通常是有问题的(这就是整个"价值限制"业务的含义),但F#允许它在某些有限的情况下 - 例如你可以写:
let empty = []
Run Code Online (Sandbox Code Playgroud)
这定义了类型的通用值'a list.需要注意的是,这会被编译为每次访问该empty值时调用的函数.我认为你的第一个nextId函数以相同的方式编译 - 所以每次访问它时都会对body进行评估.
这可能不能回答原因,但我希望它提供了一些关于如何发生这种情况的提示 - 以及在其他情况下你所看到的行为可能是明智的!
我不知道为什么编译器决定在你的第一个场景中进行推广,但最终nextId类型obj -> intvs 之间的区别'a -> int是驱动看似奇怪的行为的原因.
对于它的价值,您可以使用另一种类型注释"强制"第一个场景中的预期行为:
let nextId : obj -> int =
let mutable i = 0
let help (key:obj) =
i <- i + 1
i
help
Run Code Online (Sandbox Code Playgroud)
现在,如果你将这些值放在模块中(比如在这个要点中),编译并检查ILSpy中的程序集,你会发现除了实例化计数器的ref单元格之外,代码几乎相同:
在具体的情况下,nextId是一个产生一个函数的属性,该函数与模块的静态初始化器中的ref cell一起实例化,即所有调用nextId共享同一个计数器,
在通用情况下,nextId是一个产生函数的泛型函数,并且ref单元格在其体内实例化,即每次调用时都有一个计数器nextId.
因此,通用案例中发出的代码实际上可以使用此代码段在F#中呈现:
let nextId () =
let mutable i = 0
fun key ->
i <- i + 1
i
Run Code Online (Sandbox Code Playgroud)
最重要的是,当你有这样的通用值时,发出编译器警告是有意义的.一旦你知道问题就很容易避免这个问题,但这是你不会看到的其中一个问题.
| 归档时间: |
|
| 查看次数: |
181 次 |
| 最近记录: |