编译器覆盖F#中的类型定义(泛型)

时间:2013-06-04 15:21:02

标签: generics f# type-inference

情景1

let map = Dictionary<string,obj>()
map.Add("1",10)
map.Add("2",10L)
map.Add("3","10")

这符合罚款

情景2

let map = Dictionary<string,(unit -> obj)>()
map.Add("1",fun() -> 10)
map.Add("2",fun() -> 10L)
map.Add("3",fun() -> "10")

这里编译器说它除了obj但在遇到10

时找到了int

情景3

let map = Dictionary<string,(unit -> 'a)>()
map.Add("1",fun() -> 10)
map.Add("2",fun() -> 10L)
map.Add("3",fun() -> "10")

这里编译器接受第一个条目,但它会导致'a被约束为int,导致接下来的两个条目失败,因为它们不是int

第一个问题:为什么它在场景1中编译时没有在场景2中编译?

第二个问题:无论如何都要阻止'a在场景3中受到限制,或者是否存在某种可以使用的模式,这种模式可以在F#中的集合中实现不同类型(特别是在本例中的函数类型)?

值(obj /'a)的唯一用途是println "%A"的参数,我不明白它为什么不能。

1 个答案:

答案 0 :(得分:2)

在方案1中,编译器自动将map.Add的参数从int等转发到​​obj,因为它可以看到map.Add期望obj

在方案2中,它无法执行此操作,因为unit -> intunit -> obj没有可用的上传 - 您无法通过在函数周围手动插入upcast来进行转换。

理论上,编译器可以改变函数的主体,但是在调用map.Add时,自动插入强制转换纯粹是本地的。

您不能阻止'a在方案3中受到约束,因为运行时要求特定对象具有特定类型 - 即使您只以特定方式使用这些值,编译器和运行时也不会做那种看待它所需的全局分析。