4

我有一个实用程序函数,它将记录错误消息(包括字符串格式)与引发异常(raise现有异常或failwith使用格式化的错误消息调用,类似于下面的 logAndFailWithf 函数(尽管实际上它使用日志框架,不写入文本文件):

let logAndFailWithf exOpt =
    let logFile = new StreamWriter("log.txt")
    Printf.ksprintf <| fun message -> 
        try match exOpt with
            | Some ex -> 
                logFile.WriteLine("{0}\r\n{1}", message, ex)
                raise <| Exception(message, ex)
            | None -> 
                logFile.WriteLine(message)
                failwith message
        finally logFile.Close()

val logAndFailWithf : exOpt:#exn option -> (Printf.StringFormat<'b,'c> -> 'b)

如果直接调用此函数,则可以正常工作,如以下简单示例所示:

let s = "123x"
let x = try Int32.Parse s
        with | ex -> logAndFailWithf (Some ex) "Failed to parse string s: %s" s

System.Exception: Failed to parse string s: "123x" ---> 
    System.FormatException: Input string was not in a correct format.
    at System.Number.StringToNumber(String str, NumberStyles options, 
    NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
    at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)

然而,在现实世界的场景中,日志函数被传递给另一个函数,当它遇到异常时使用它来记录和抛出异常,类似于以下内容:

let exmaple param1 param2 (log: exn option -> Printf.StringFormat<_,_> -> _) =
    let x = try Int32.Parse param1
            with | ex -> log (Some ex) "Failed to parse param1: \"%s\"" param1

    let y = try Int64.Parse param2
            with | ex -> log (Some ex) "Failed to parse param2: \"%s\"" param2

    printfn "Successfully Parsed Parameters:  param1 = %d; param2 = %d" x y

在这种情况下,编译器会在第二个 let 绑定 ( ) 上报告错误,let y = ...并显示以下消息:

error FS0001: This expression was expected to have type
    'int64'    
but here has type
    'int'

这似乎发生在与 log 函数的第一次使用不具有相同类型的表达式中任何 log 函数的使用(在上面的示例中,int64when bindingy而不是intwhen binding x),我无法找到一种表达log参数类型的方法,该方法既与函数的签名相匹配,logAndFailWithf又在同一函数中用于不同类型的表达式时起作用。

如何将此隐式泛型函数作为参数传递给其他函数,以便可以在不同类型的表达式中调用它?

4

0 回答 0