F#神秘约束错误消息

时间:2015-02-27 09:56:45

标签: f#

为了好玩,我一直在玩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()

但我收到以下错误:

  1. 签名和实现不兼容,因为类/签名中的type参数对成员/实现中的类型参数有不同的编译时要求
  2. 签名和实现不兼容,因为声明了类型参数&#39; T&#39;需要表单的约束(Next或^ T):(静态成员(++):下一步* ^ T - &gt; ^?155882)
  3. 我对第二个错误试图说的更感兴趣。什么神秘的^?155882是什么意思?我猜测它可能与无法解析类型有关。此外,假设它试图推断约束为:

    (Next or  ^T) : (static member ( ++ ) : Next *  ^T ->  ^T)
    

    甚至可以指定&#34;或&#34;条件使用when 'T:...?我无法找出有效的语法。

    最后,^ T建议statically resolved type parameter,但文档说它们不能用于类型。尽管如此,我还是尝试将“T”更改为“^ T”,但仍然遇到相同的错误。

    我意识到这个例子滥用了类型系统,所以我并不是说编译器应该能够处理它。但是,为了我自己的兴趣,我想知道错误信息的真正含义!

1 个答案:

答案 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的实例的函数添加参数来禁用它。

相关问题