F#递归类型:方法与函数类型推断的差异

F#递归类型:方法与函数类型推断的差异,f#,type-inference,recursive-datastructures,recursive-type,F#,Type Inference,Recursive Datastructures,Recursive Type,有人能解释一下为什么在F#类型推断中,类方法和函数之间的工作方式不同(或者我不理解的其他方面) 想象一下如下(简化): 在自由浮动函数add中,泛型类型参数属于函数本身(add) 为什么这很重要?因为当您引用函数本身时,除非另有指定,否则编译器假定类型参数不变。它不会猜出另一个,因为这可能会隐藏大量类型不匹配错误 但是,对于函数所属的类型,它没有做出相同的假设 如果检查参数,则对add的调用假定为对add.add的调用。这是一个完全不同的函数调用 如果显式注释类型: static member

有人能解释一下为什么在F#类型推断中,类方法和函数之间的工作方式不同(或者我不理解的其他方面)

想象一下如下(简化):


在自由浮动函数
add
中,泛型类型参数属于函数本身(
add

为什么这很重要?因为当您引用函数本身时,除非另有指定,否则编译器假定类型参数不变。它不会猜出另一个,因为这可能会隐藏大量类型不匹配错误

但是,对于函数所属的类型,它没有做出相同的假设

如果检查参数,则对
add
的调用假定为对
add.add
的调用。这是一个完全不同的函数调用

如果显式注释类型:

static member Add (value : 'T) (tree : Tree<'T>) : Tree<'T> =
    // ...
    | Deep (Two (b, a), deeper) -> Deep (One value, deeper |> Tree<'T>.Add (Node2 (b, a)))
静态成员添加(值:'T)(树:树=
// ...
|Deep(两个(b,a),更深)->Deep(一个值,更深|>Tree=
// ...
|Deep(两个(b,a),Deep)->Deep(一个值,Deep |>this.Add(Node2(b,a)))
反之亦然,您可以通过注释类型参数来编译自由函数,这样编译器就不会假设“它是相同的符号,所以必须引用相同的值”:

让rec添加=
// ...
|Deep(两(b,a),Deep)->Deep(一个值,Deep |>add(Node2(b,a)))

实际上,即使只是在函数绑定中添加类型参数'let rec addOh,很好。似乎编译器只会在名称完全相同的情况下进行相同的实例假设。我更正了我的答案。
Type mismatch. Expecting a
    Tree<Node<'T>> -> Tree<Node<'T>>    
but given a
    Tree<'T> -> Tree<'T>    
The resulting type would be infinite when unifying ''T' and 'Node<'T>'
static member Add (value : 'T) (tree : Tree<'T>) : Tree<'T> =
    // ...
    | Deep (Two (b, a), deeper) -> Deep (One value, deeper |> Tree<'T>.Add (Node2 (b, a)))
member this.Add (value : 'T) (tree : Tree<'T>) : Tree<'T> =
    // ...
    | Deep (Two (b, a), deeper) -> Deep (One value, deeper |> this.Add (Node2 (b, a)))
let rec add<'T> (value : 'T) (tree : Tree<'T>) : Tree<'T> =
    // ...
    | Deep (Two (b, a), deeper) -> Deep (One value, deeper |> add (Node2 (b, a)))