为什么F#不能在这种情况下推断出类型?

时间:2014-11-23 20:17:40

标签: f#

考虑以下示例代码,其中我有一个泛型类型和2个静态成员构造函数,用于创建所述类型的专用实例。

type Cell<'T> = { slot: 'T }
with
    static member CreateInt x : IntCell  = { slot = x }
    static member CreateString x : StringCell = { slot = x}
and IntCell = Cell<int>
and StringCell = Cell<string>

// Warnings on the next 2 lines
let x = Cell.CreateInt 123
let y = Cell.CreateString "testing"

我认为我有必要的类型注释,但F#给了我警告。 E.g:

Warning 2 The instantiation of the generic type 'Cell' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. 'Cell<_>'.

如何让警告消失?

2 个答案:

答案 0 :(得分:4)

正如@ildjarn暗示的那样,Cell是泛型类型,编译器在调用静态成员时想知道类型'T

// Two ways to fix the compiler warning
let x = Cell<int>.CreateInt 123
let y = StringCell.CreateString "testing"

避免指定'T的方法是将创建函数移动到模块中。

type Cell<'T> = { slot: 'T }
type IntCell = Cell<int>
type StringCell = Cell<string>
module Cell =
    let createInt x : IntCell = { slot = x }
    let createString x : StringCell = { slot = x }

let x = Cell.createInt 123
let y = Cell.createString "testing"

但是,由于您无论如何都要在函数名中指定所需的类型,因此可能首选以下语法。

type Cell<'T> = { slot: 'T }
with
    static member Create (x : 'T) = { slot = x }
type IntCell = Cell<int>
type StringCell = Cell<string>

let x = IntCell.Create 123
let y = StringCell.Create "testing"

// or simply
let z = Cell<float>.Create 1.0

感谢@Vandroiy指出我的Create方法中缺少的类型约束,以及他的答案,该答案显示了编译器如何能够推断'T泛型类型Cell由被调用的静态方法决定。

答案 1 :(得分:4)

编译器无法确定方法'TCreateInt的通用参数CreateFloat,因为它与方法&#39;无关。返回类型。在这个问题中,写下来是有效的:

Cell<float>.Create 1.0 // useless type annotation to remove warning

但是,您也可以写

Cell<string>.Create 1.0 // Trollolol

为避免这种情况,您需要确保工厂只能生成调用它的类型。在泛型类型上声明工厂时,使用类型注释将其返回类型的泛型参数与其调用类型的泛型参数等同。

在我看来,复杂的表述增加了混乱。您可以使用

达到预期的效果
type Cell<'T> =
    { slot: 'T }
    static member Create (x : 'T) = { slot = x }

let x = Cell.Create 123
let y = Cell.Create "testing"

请注意x的类型注释,它将工厂的输入类型与Cell<>类型的通用参数等同起来!

编辑发表评论:

原样,IntCellStringCell类型没有用处;它们只是Cell<int>Cell<string>的可读性较差的形式。从评论到这个答案,我知道应该公开这些类型而不是Cell。据我所知,如果在问题中定义它们是不可能的,因为类型缩写最多具有它们缩写的类型的可访问性。

这是一个合理的设计选择:如果类型是通用的,它应该接受所有有效的泛型类型参数。如果IntCellStringCell添加了专门的实现,通常的方法是将它们组合成Cell类型及其专用特性的适当实例。然后,允许Cell类型具有比专用类型更受限制的可访问性。