2015-11-20 149 views
1

这个函数有签名:(UnionCaseInfo -> bool) -> 'T option为什么在这里需要类型注释?

let private findCase<'T> f = 
    match FSharpType.GetUnionCases typeof<'T> |> Array.filter f with 
     |[|case|] -> Some (FSharpValue.MakeUnion(case,[||]) :?> 'T) 
     |_ -> None 

此功能,它调用上述功能,具有签名:int -> obj

let CreateFromId<'T> id = 
    match findCase (fun case -> case.Tag = id) with 
     | Some c -> c 
     | None -> failwith (sprintf "Lookup for union case by \"%d\" failed." id) 

在用于CreateFromId图案,智能感知显示c被推断即使它显示findCase的正确签名,也是obj类型。为什么这种类型似乎在模式中“失去”了?

回答

1

因为类型参数'T没有在函数体中引用(我可以通过指定的CreateFromId'T返回类型解决此),所以类型推断有没有办法知道你的意图是名称'T返回类型。

所以,你可以在身体的返回类型添加它(因为你已经理解了它),或从声明中删除:

let CreateFromId id = ... 

通过消除它的工作原理,因为F#进行自动的概括,在只是不同的是它会为类型变量使用一个任意名称,但即使您想要命名该类型变量'T我会做的是将其添加为返回类型,但是在括号内的声明中没有:

let CreateFromId id : 'T = ... 
+0

这很有道理。我想我需要有类型参数,因为'FSharpType.GetUnionCases'需要它。 –

0

CreateFromId的类型是i由int -> obj推断,因为没有什么“链接”你的函数上的两个'T类型参数。

findCase通过'T正确通用,但CreateFromId只声明为通用,并且从不使用泛型类型参数。

使用所需的类型注释功能足以使类型排列起来。您也可以拨打findCase明确提供类型:

let CreateFromId<'T> id = 
    match findCase<'T> (fun case -> case.Tag = id) with 
    | Some c -> c 
    | None -> failwith (sprintf "Lookup for union case by \"%d\" failed." id) 

或者为对方的回答表明,刚刚从CreateFromId删除'T并让类型推断做它的事。