2016-09-26 38 views
3

我已经遇到了这些错误before in a much more complex scenario。从那以后,我简化了很多东西,并且有很长时间的工作代码,直到我需要覆盖Equals。它使用了F#似乎不喜欢的内联成员。使用内联类型成员失败,FS1114,FS1113,FS1116,FS1118

基本上,该方案可归纳为以下代码:

[<Flags>] 
type MyType = 
    | Integer = 0b0001 
    | Float = 0b0010 

module Test = 
    [<CustomEquality;NoComparison>] 
    type SomeType = 
     | Int of int64 
     | Float of float 

     override x.Equals other = 
      match other with 
      | :? SomeType as y -> 
       // following line throws on compiling this 
       match SomeType.getType x &&& SomeType.getType y with 
       | MyType.Integer -> int64 x = int64 y  // highest type is integer (both are int) 
       | MyType.Float -> float x = float y   // highest type is float (either is or both are float) 
       | _ -> false // impossible 
      | _ -> false 

     override x.GetHashCode() = 
      match x with Int i -> hash i | Float f -> hash f 

     static member inline op_Explicit(n: SomeType): float = 
      match n with 
      | Int i -> float i 
      | Float f -> f 

     static member inline op_Explicit(n: SomeType): int64 = 
      match n with 
      | Int i -> i 
      | Float f -> int64 f 

     static member inline getType x = 
      match x with 
      | Int _ -> MyType.Integer 
      | Float _ -> MyType.Float 

以下错误提出了(这有点像我刚才的问题而是涉及复杂的鸭子类型)。

错误FS1114:值“Test.SomeType.getType”被内嵌标记,但在优化环境没有义务
错误FS1113:值“的getType”被内嵌标记,但其实现使用内部的或私人功能不足
警告FS1116:标记为'inline'的值具有意外值
错误FS1118:未内联标记为'inline'的值'getType',可能是因为递归值标记为' inline'

现在,没有递归值,并且目标类型是已知的(由于在匹配模式中隐式转换为SomeType),所以我认为没有理由使这种内联是不可能的。

有没有人有这方面的想法?或者一个模式,包括内联op_Explicit(如果您删除getType,您将会得到这些错误),最好是getType内联?我知道我可以通过一个面向对象的层次结构来解决这个问题,但是我宁愿使用这种方法,为了清晰起见(类型系统是一个晶格,而不是层次结构)和性能(更早带有内联的版本显示测试场景速度提高了4倍以上,并且速度很重要)。

在事后,下面,简单的场景也会引发这些错误:

module Test = 
    type SomeType = 
     | Int of int64 
     | Float of float 

     static member MyEquals (x, other: SomeType) = 
      // following line throws on compiling this 
      float x = float other 

     static member inline op_Explicit(n: SomeType): float = 
      match n with 
      | Int i -> float i 
      | Float f -> f 

     static member inline op_Explicit(n: SomeType): int64 = 
      match n with 
      | Int i -> i 
      | Float f -> int64 f 

当我删除类型装饰other: SomeType,错误消失。我不知道为什么这很重要,因为具有相同静态推断方法的较窄类型不应引起这个错误,我想。

而且由于override x.Equals的类型注释为obj,所以我没有看到如何使用该知识(删除类型装饰)来帮助我。

+1

您可以通过不使用'function'并使用显式参数+'match'来解决此问题。函数产生一个值;值不能内联。静态成员inline getType x =匹配x与Int _ - > MyType.Integer | Float _ - > MyType.Float' – ildjarn

+1

@ildjarn,感谢您的建议,但这并不会改变错误,尝试它,并将其复制到FSI中。但是你是对的,有时'inline'与'function'(静态成员)一起工作,有时不能(绑定),不知道为什么,[有一个功能请求允许内联'let f = fun x - > ... '](HTTPS://fslang.uservoice。com/forums/245727-f-language/suggestions/6237585-allow-inline-keyword-in-the-case-let -f-fun-a),但那是另一回事。无论哪种方式,错误依然存在。 – Abel

+1

@ildjarn,顺便说一句,我更新了Q.(实施你的建议),以避免错误从何而来。没有编译,F#编辑器,推理和智能感知,不要抱怨。 – Abel

回答

2

似乎是F#编译器无法与无序代码进行内联。正如你在下面的评论中正确地指出这似乎是一个错误。

open System 

[<Flags>] 
type MyType = 
    | Integer = 0b0001 
    | Float = 0b0010 

module Test = 
    [<CustomEquality;NoComparison>] 
    type SomeType = 
     | Int of int64 
     | Float of float 

     static member inline op_Explicit(n: SomeType): float = 
      match n with 
      | Int i -> float i 
      | Float f -> f 

     static member inline op_Explicit(n: SomeType): int64 = 
      match n with 
      | Int i -> i 
      | Float f -> int64 f 

     static member inline getType x = 
      match x with 
      | Int _ -> MyType.Integer 
      | Float _ -> MyType.Float 

     override x.Equals other = 
      match other with 
      | :? SomeType as y -> 
       // following line throws on compiling this 
       match SomeType.getType x &&& SomeType.getType y with 
       | MyType.Integer -> int64 x = int64 y  // highest type is integer (both are int) 
       | MyType.Float -> float x = float y   // highest type is float (either is or both are float) 
       | _ -> false // impossible 
      | _ -> false 

     override x.GetHashCode() = 
      match x with Int i -> hash i | Float f -> hash f 
+2

这是正确的,它解决了这个问题,但代码顺序不是_incorrect_:在一个类中,在具有'和'的类之间,顺序是不相关的。我昨天[报道这是一个F#的bug](https://github.com/Microsoft/visualfsharp/issues/1565),我们似乎得出了大致相同的结论:)。 – Abel

+0

这是正确的。感谢您报告错误。我最好的猜测是,甚至在解析模块代码时,F#编译器也试图在不知道它的实现的情况下内联函数,这当然会失败。 – CodeMonkey