此示例代码:
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"但是它似乎没有那样工作。
答案 0 :(得分:3)
函数modifyX
不正确。您不能在定义中使用术语X
,并让X
引用不同的字段。
F#规范的第6.3.6节
每个字段标签必须解析为单个记录类型R中的字段Fi,其所有字段均可访问。
通过将recordA
和recordB
传递给modifyX
,X
并不是唯一确定为单一字段的字段。
您真正想要的可能是通过接口继承的多态属性成员,而不是具有公共成员名称的一组记录类型。
答案 1 :(得分:1)
问题是编译器根据用法推断modifyX
的类型。我的理解是,这是自下而上的,因此推断类型为val modifyX : newX:string -> record:recordB -> recordB
。当然,这在尝试将其与类型recordA
的记录一起使用时会导致类型错误。警告告诉你,虽然它选择了一个类型,但是有另一种类型具有相同的字段,所以编译器所能做的就是最好地猜测你的意思。有可能实现您尝试使用内联函数执行的操作,但我不确定这可能会如何起作用。
答案 2 :(得分:1)
使这项工作所需的内联魔法基于重载决策和静态解析member constraints。定义为operators的重载避免了拼写显式约束的需要。
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'
这并非真正用于实际用途。听取建议,并探讨其他方法是否更适合您的问题。