Compiler can't tell which record type with duplicate fields should be the function parameter type

杀马特。学长 韩版系。学妹 提交于 2019-12-11 11:56:19

问题


My program has a few record types with the same field names (each record type means something different). The compiler insists function parameters matching this record shape must be of the last type declared, even though I'm declaring record instances with unambiguous field names, and always passing a consistent type into each function.

What is the appropriate way to deal with this? I know I could put a type annotation on the functions, but I feel like if I'm doing things the Right Way, I shouldn't need to fight the compiler with type annotations.

Minimum code demonstrating the problem:

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

let getX t =
    t.x

getX {type1.x=1}
|> ignore

Compiler output:

$ 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    

回答1:


There are a few ways around this:

  1. Type annotations as you suggested:

    let getX (t : type1) =
        t.x
    
  2. Define getX before the conflicting type is defined:

    type type1 = {x:int}
    
    let getX t =
        t.x
    
    type type2 = {x:int}
    
  3. Don't explicitly specify the type when calling the function:

    getX {x=1}
    

Which of these options is the 'right' way depends a lot on the precise situation.




回答2:


In addition to the answer by p.s.w.g, you might consider using modules to partition the scope.

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

I would say that, in F#, having two records with the same labels in the same namespace is a bit of a code smell.




回答3:


You could use a constraint on getX:

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

However trying to make it more generic (instead of requiring the property x to be int):

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

has issues with the F# interpreter, compiler and runtime.

The F# interpreter bombs out, the compiler thinks that getX_generic returns an obj instead of int, and when you do run it, it does not compute.

F# being a new language has a few bugs - if you want this to work - I would suggest you log these issues in a bug report.



来源:https://stackoverflow.com/questions/24984247/compiler-cant-tell-which-record-type-with-duplicate-fields-should-be-the-functi

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!