Generics Gerenics将参数从';a至obj

Generics Gerenics将参数从';a至obj,generics,f#,constraints,Generics,F#,Constraints,鉴于此功能: let endFlow x = match x with | Ok o -> () | Error (e: string) -> exn e |> raise let endFlow<'a, 'T when 'T :> exn> (mkExn : string -> 'T) (x : Result<'a, string>) = match x with | Ok o

鉴于此功能:

let endFlow x = 
    match x with
    | Ok o -> ()
    | Error (e: string) ->
        exn e |> raise
let endFlow<'a, 'T when 'T :> exn> (mkExn : string -> 'T)  (x : Result<'a, string>) = 
    match x with
    | Ok o -> ()
    | Error (e: string) ->
       mkExn e |> raise
x被决定为结果提升 现在x被解析为
结果

我是否可以在没有参数obj约束的情况下使用泛型?

这是因为您只定义了一个泛型参数。没有'a可以说

以前,当您没有指定任何泛型参数时,编译器可以自由地发明它需要的任何东西来正确地泛化代码。但是,既然您明确表示您的函数只有一个泛型参数
'T
,编译器就不能直接插入并添加一个
'a
——这将更改您指定的签名

因此,让我们帮助编译器完成并添加一个
'a
参数:

let endFlow<`a, 'T when 'T :> exn> x = 
现在签名正是你想要的

然而,即使像这样修复了它,它仍然不会像您期望的那样工作。你看,表达式
exn e:?>'T
并不像你想象的那样

表达式
exn e
将创建类型为
exn
(又称
System.Exception
)的对象,然后尝试将其强制转换为未知类型
'T
。底层对象肯定不是类型
'T
(我们已经知道它是类型
exn
),因此这种转换的结果将是
null
。和你想象的不太一样,是吗

想想看,你怎么知道类型为
'T
的异常完全可以用字符串构造出来呢

如果您确实想抛出调用方定义类型的异常,则必须提供构造此类异常的方法,即提供构造函数:

let endFlow x = 
    match x with
    | Ok o -> ()
    | Error (e: string) ->
        exn e |> raise
let endFlow<'a, 'T when 'T :> exn> (mkExn : string -> 'T)  (x : Result<'a, string>) = 
    match x with
    | Ok o -> ()
    | Error (e: string) ->
       mkExn e |> raise
let endFlow
let r : Result<int, string> = ...
r |> endFlow exn      // throws System.Exception
r |> endFlow System.InvalidOperationException    // throws System.InvalidOperationException