移动递归类型时代码中断

Nik*_*ird 2 f#

在重构某些代码的过程中,我注意到一种情况,当移动时代码中断:

type ThingBase () = class end

and Functions =
    static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () = new 'T ()

and Thing () =
    inherit ThingBase ()
    static member Create () = Functions.Create<Thing> ()

// This works, but try moving the Functions type here instead.
Run Code Online (Sandbox Code Playgroud)

如果您移动Functions类型下面的Thing类型,代码会意外中断:

type ThingBase () = class end

and Thing () =
    inherit ThingBase ()
    static member Create () = Functions.Create<Thing> ()
//                            ^^^^^^^^^^^^^^^^^^^^^^^^^^
// This construct causes code to be less generic than indicated by the
// type annotations. The type variable 'T has been constrained to be
// type 'Thing'.

and Functions =
    static member Create<'T when 'T :> ThingBase and 'T : (new : Unit -> 'T)> () = new 'T ()
//                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// The type ''T' does not match the type 'Thing'.
Run Code Online (Sandbox Code Playgroud)

无论我尝试什么,我都无法做到这一点.为什么类型推断如此顽固并拒绝概括该Create方法.

顺便说一句,我也尝试过F#4.1 module rec,如果Create模块中的函数也是无关紧要的.

任何见解?对我而言,这似乎应该是编译器应该没有任何麻烦的东西.

Bri*_*ian 6

如果你这样做,它将编译

static member Create<'T when 'T :> ThingBase 
         and 'T : (new : Unit -> 'T)> () : 'T = new 'T ()
//                                       ^^^^          
Run Code Online (Sandbox Code Playgroud)

返回类型明确说明的地方.

递归定义在两次传递中从左到右进行类型检查; 第一个函数/方法签名,然后是主体.您需要body(或显式返回类型注释)来获取结果类型,因此您需要首先使用主体,或者需要注释,以便在两次传递的第一个中获得解析.