为了好玩,我一直在玩F#中的类型类,使用显示here的想法。我创建了一个Next类型类来表示具有"后继的"例如下一个1 = 2,今天下一个=明天等:
type Next = Next with
static member (++) (Next, x:int) = x + 1
static member (++) (Next, x:DateTime) = x.AddDays 1.0
let inline next x = Next ++ x
let v1 = next 1 // v1 = 2
let v2 = next DateTime.Now // v2 = Now + 1 day
现在我想使用" nextable"泛型类中的类型:
type UsesNextable<'T>(nextable: 'T) = // Compile error 1
member inline this.Next =
let v = next nextable // Compile error 2
v.ToString()
但我收到以下错误:
我对第二个错误试图说的更感兴趣。什么神秘的^?155882是什么意思?我猜测它可能与无法解析类型有关。此外,假设它试图推断约束为:
(Next or ^T) : (static member ( ++ ) : Next * ^T -> ^T)
甚至可以指定&#34;或&#34;条件使用when 'T:...
?我无法找出有效的语法。
最后,^ T建议statically resolved type parameter,但文档说它们不能用于类型。尽管如此,我还是尝试将“T”更改为“^ T”,但仍然遇到相同的错误。
我意识到这个例子滥用了类型系统,所以我并不是说编译器应该能够处理它。但是,为了我自己的兴趣,我想知道错误信息的真正含义!
答案 0 :(得分:5)
问题是.NET不支持静态约束。 F#解析它们内联函数,这些函数被编译为静态方法,但不能将其编码为标准.NET类型。在您的代码中,您要创建的泛型类型将具有一个带有.NET无法表示的静态约束的类型参数。
您可以将方法更改为静态,它可以正常工作:
type UsesNextable() =
static member inline Next(nextable) =
let v = next nextable
v.ToString()
如果需要,您的类型仍然可以是通用的,但是您应该避免引用具有静态约束的类型的类型参数,例如这将起作用:
type UsesNextable<'T>() =
static member inline NextOf(n:'U) = let v = next n in v.ToString()
但不是这样:
type UsesNextable<'T>() =
static member inline NextOf(n:'T) = let v = next n in v.ToString()
解决了第一个问题后,您将看到两个错误消息都消失了,因为第二个问题与第一个错误消息相关,其中类型系统无法对约束进行编码,但现在它可以单独解决。 ^?155882
表示类型系统无法推断的静态约束类型变量。
请注意,从'T
更改为ˆT
并不会改变任何内容,实际上两者都指的是相同的类型变量,唯一的事情就是您被迫使用<调用方法时,em> hat 。
最后关于你不能写的事实:
let inline next v = ((Next or ^T) : (static member ( ++ ) : Next * ^T -> ^T) Next, v)
这显然是一个错误,因为F#可以推断它,但你不能写它不一致。我前段时间已经报道了,他们告诉我他们将来会修复它。
有许多方法可以通过强制F#推断类型而不是直接编写来解决这个限制,这里是一个单线解决方案:
let inline next v = ((^Next or ^T) : (static member ( ++ ) : ^Next * ^T -> ^T) Next, v)
它会创建一个警告但您可以通过nowarn指令或通过向包含类型Next
的实例的函数添加参数来禁用它。