F# kprintf:缺少有关冗余参数的警告

Gos*_*win 3 f#

有没有办法使用 kprintf (或类似的)对异常进行字符串格式化,并且仍然收到有关冗余参数的警告?到目前为止我有:

type MyException (s:string) = 
    inherit System.Exception(s)
    static member Raise msg =   
        Printf.kprintf (fun s -> raise (MyException(s))) msg
        
do
    MyException.Raise "boom %d" 9 1 // Gives NO warning about redundant arguments
    failwithf         "boom %d" 9 1 // Gives warning about redundant arguments
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用新的 $ 格式,但希望与旧版本的 F# 保持兼容。

Abe*_*bel 5

问题不是来自kprintf,而是来自raise,它允许函数的返回类型是任何类型,包括柯里化函数。该函数failwithf将此警告作为特殊情况。

\n

如果你返回,让\xe2\x80\x99s,一个字符串或一个单位,你实际上会得到一个错误。缺点是现在你不能再在每个位置加注,因为返回参数不再是通用的。

\n

您可以通过强制使用类型参数来解决这个问题,但这对于调用者来说不太理想。

\n

例如,这可行,但如果将 的返回类型更改f为字符串,则会失败:

\n
open System\ntype MyException (s:string) = \n    inherit System.Exception(s)\n    static member Raise msg =   \n        Printf.kprintf (fun s -> raise (MyException s) |> ignore) msg\n        \nmodule Test =\n    let f() : unit = // string won\xe2\x80\x99t work\n         MyException.Raise "boom %d" 9 10 // error, as expected\n
Run Code Online (Sandbox Code Playgroud)\n

编辑:解决方法

\n

这是某种解决方法。您可以使用泛型类型约束来限制类型,并利用 F# 函数类型不可比较或不可等价、没有适当值的事实null

\n

由于 F# 强大的结构相等支持,您将使用的大多数类型都是可相等的。类型约束的其他选项包括struct(仅限结构)null(不包括记录和 DU 类型)或某个继承约束(如果适合您的用例)。

\n

例子:

\n
type MyException (s:string) = \n    inherit System.Exception(s)\n\n    static member Raise<\'T when \'T : equality> msg =   \n        let raiser s =\n            raise (MyException s)\n            Unchecked.defaultof<\'T> // fool the compiler\n\n        Printf.kprintf raiser msg\n        \nmodule Test =\n    let f() = MyException.Raise "boom %d" 9\n    let g() = MyException.Raise "boom %d" 9 10  // error\n
Run Code Online (Sandbox Code Playgroud)\n

除了类型限制之外,缺点是您收到的错误将是类型错误,而不是您请求的警告。

\n