在 FS1114、FS1113、FS1116、FS1118 中使用内联类型成员失败
Using inline within type members fails with FS1114, FS1113, FS1116, FS1118
我一直被这些错误击中 。从那时起,我简化了很多事情,并且有很长时间的工作代码,直到我需要重写 Equals
。它使用 F# 似乎不喜欢的内联成员。
基本上,场景可以用以下代码概括:
[<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
出现了以下错误(这与我之前的问题类似,但涉及复杂的 ducktyping)。
error FS1114: The value 'Test.SomeType.getType' was marked inline but was not bound in the optimization environment
error FS1113: The value 'getType' was marked inline but its implementation makes use of an internal or private function which is not sufficiently accessible
warning FS1116: A value marked as 'inline' has an unexpected value
error FS1118: Failed to inline the value 'getType' marked 'inline', perhaps because a recursive value was marked 'inline'
现在,没有递归值,并且目标类型是已知的(作为匹配模式中隐式转换为 SomeType
的结果),所以我认为没有理由这样做内联是不可能的。
有人对此有什么想法吗?或者一个模式,包括内联的 op_Explicit
(如果你删除 getType
,你会得到那些错误)并且最好还有内联的 getType
?
我知道我可以用 OO 层次结构、接口等等来解决这个问题,但我宁愿使用这种方法,既是为了清晰(类型系统是一个格子,而不是层次结构)也是为了性能(一个带有内联的早期版本在测试场景中显示速度提高了 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
的类型注释,我不知道如何使用该知识(删除类型装饰)来帮助我。
似乎是 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
我一直被这些错误击中 Equals
。它使用 F# 似乎不喜欢的内联成员。
基本上,场景可以用以下代码概括:
[<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
出现了以下错误(这与我之前的问题类似,但涉及复杂的 ducktyping)。
error FS1114: The value 'Test.SomeType.getType' was marked inline but was not bound in the optimization environment
error FS1113: The value 'getType' was marked inline but its implementation makes use of an internal or private function which is not sufficiently accessible
warning FS1116: A value marked as 'inline' has an unexpected value
error FS1118: Failed to inline the value 'getType' marked 'inline', perhaps because a recursive value was marked 'inline'
现在,没有递归值,并且目标类型是已知的(作为匹配模式中隐式转换为 SomeType
的结果),所以我认为没有理由这样做内联是不可能的。
有人对此有什么想法吗?或者一个模式,包括内联的 op_Explicit
(如果你删除 getType
,你会得到那些错误)并且最好还有内联的 getType
?
我知道我可以用 OO 层次结构、接口等等来解决这个问题,但我宁愿使用这种方法,既是为了清晰(类型系统是一个格子,而不是层次结构)也是为了性能(一个带有内联的早期版本在测试场景中显示速度提高了 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
的类型注释,我不知道如何使用该知识(删除类型装饰)来帮助我。
似乎是 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