编译器不能告诉哪个具有重复字段的记录类型应该是函数参数类型

时间:2014-07-27 18:33:47

标签: f# record

我的程序有一些具有相同字段名称的记录类型(每种记录类型意味着不同的东西)。编译器坚持认为匹配此记录形状的函数参数必须是声明的最后一个类型,即使我声明具有明确字段名称的记录实例,并且始终将一致类型传递给每个函数。

处理此问题的适当方法是什么?我知道我可以在函数上添加类型注释,但我觉得如果我正在以正确的方式做事,我不需要使用类型注释来对抗编译器。

证明问题的最低代码:

type type1 = {x:int}
type type2 = {x:int}

let getX t =
    t.x

getX {type1.x=1}
|> ignore

编译器输出:

$ fsharpc --nologo test.fs


/tmp/typetest/test.fs(7,6): error FS0001: This expression was expected to have type
    type2    
but here has type
    type1    

3 个答案:

答案 0 :(得分:2)

有几种解决方法:

  1. 按照建议输入注释:

    let getX (t : type1) =
        t.x
    
  2. 在定义冲突类型之前定义getX

    type type1 = {x:int}
    
    let getX t =
        t.x
    
    type type2 = {x:int}
    
  3. 调用函数时不要明确指定类型:

    getX {x=1}
    
  4. 这些选项中的哪一个是正确的'方式很大程度上取决于具体情况。

答案 1 :(得分:2)

除了p.s.w.g的答案之外,您可以考虑使用模块 分区范围。

module A =
    type type1 = {x:int}

module B =
    type type2 = {x:int}

module C =
    // only make type1 visible in C
    open A  

    let getX t =
        t.x

    getX {type1.x=1}
    |> ignore

我会说,在F#中,有两个记录 在同一名称空间中使用相同的标签会有点代码味道。

答案 2 :(得分:0)

您可以在getX上使用constraint

let inline getX (t: ^T) =
    (^T : (member x: int) (t))

但是尝试使其更通用(而不是要求属性xint):

let inline getX_generic (t: ^T) : 'U = 
    (^T : (member x : 'U) (t))

有F#解释器,编译器和运行时的问题。

F#解释器爆炸,编译器认为getX_generic返回obj而不是int,当你运行它时,它不会计算。

F#是一种新语言有一些错误 - 如果你想让它起作用 - 我建议你在错误报告中记录这些问题。