[英]Why doesn't F# infer the record type when updating a record?
此示例代码:
type recordA = { X: string; }
type recordB = { X: string; }
let modifyX newX record = { record with X = newX }
let modifiedRecordA = {recordA.X = "X"} |> modifyX "X2"
let modifiedRecordB = {recordB.X = "X"} |> modifyX "X2"
结果是:
let modifyX newX record = { record with X = newX }
--------------------------^^^^^^^^^^^^^^^^^^^^^^^^
stdin(4,27): warning FS0667: The field labels and expected type of this record expression or pattern do not uniquely determine a corresponding record type
let modifiedRecordA = {recordA.X = "X"} |> modifyX "X2"
-------------------------------------------^^^^^^^^^^^^
stdin(6,44): error FS0001: Type mismatch. Expecting a
recordA -> 'a
but given a
recordB -> recordB
The type 'recordA' does not match the type 'recordB'
我的期望是,modifiedRecordA最终等同于{recordA.X =“ X2”},modifiedRecordB最终等同于{recordB.X =“ X2”},但这似乎并不起作用。
函数modifyX
不正确。 您可能没有在定义中使用术语X
,而是让X
引用了不同的字段。
F#规范的第6.3.6节
每个字段标签必须解析为单个记录类型R中的字段Fi,所有字段都可以访问。
通过将recordA
和recordB
传递给modifyX
, X
不会唯一地确定为单一类型的字段。
您真正想要的可能是通过接口继承的多态属性成员,而不是一组具有公共成员名的记录类型。
问题在于,编译器根据使用情况推断了modifyX
的类型。 我的理解是,这是自下而上进行的,因此推断类型为val modifyX : newX:string -> record:recordB -> recordB
。 当尝试将它与recordA
类型的记录一起使用时,这当然会导致类型错误。 警告告诉您,尽管它选择了一个类型,但还有另一个具有相同字段的类型,因此编译器可以做的就是尽最大可能猜测出您要输入的类型。 可能可以使用内联函数实现您要执行的操作,但是我不确定这可能会立即起作用。
进行此工作所需的内联魔术基于过载解析和静态解析的成员约束 。 定义为运算符的重载避免了阐明明确的约束的需要。
type Foo = Foo with
static member ($) (Foo, record) = fun newX -> { record with recordA.X = newX }
static member ($) (Foo, record) = fun newX -> { record with recordB.X = newX }
let inline modifyX newX record = (Foo $ record) newX
let modifiedRecordA = {recordA.X = "X"} |> modifyX "X2"
let modifiedRecordB = {recordB.X = "X"} |> modifyX "X2"
传递不存在重载的类型的构造不编译。
type recordC = { X: string; }
let modifiedRecordC = {recordC.X = "X"} |> modifyX "X2"
// Error No overloads match for method 'op_Dollar' ...
// Possible overload ... The type 'recordC' is not compatible with the type 'recordB'
// Possible overload ... The type 'recordC' is not compatible with the type 'recordA'
这并不是真正的实际用途。 注意建议并探索其他方法是否更适合您的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.