F# 中 kprintf 的语法问题

syntax issue around kprintf in F#

我有一个使用 NLog 的项目,记录器周围有一个包装器,以便在某些区域关闭注销:

member this.SetQuiet q = quiet <- q

member this.Trace format = Printf.kprintf (fun s -> if not quiet then logger.Trace(s)) format
member this.Debug format = Printf.kprintf (fun s -> if not quiet then logger.Debug(s)) format
member this.Info  format = Printf.kprintf (fun s -> if not quiet then logger.Info(s))  format
member this.Warn  format = Printf.kprintf (fun s -> if not quiet then logger.Warn(s))  format
member this.Error format = Printf.kprintf (fun s -> if not quiet then logger.Error(s)) format
member this.Fatal format = Printf.kprintf (fun s -> if not quiet then logger.Fatal(s)) format

效果很好,但我有一个问题:

logger.Info "hello"
logger.Info <| "hello"

将正常工作,而:

"hello" |> logger.Info

将不会编译并出现此错误:

typecheck error The type 'string' is not compatible with the type 'Printf.StringFormat<'a,string>'

有人能解释一下为什么会失败吗?这里仍然应该遵守 kprintf-continuation-format 的顺序,不是吗?

有解决办法吗?原因是我试图做一个 'tee' 以非冗长的方式记录消息(T 恤只是应用一个函数然后 returns 原始参数):

"my messsage"
|> tee logger.Info
|> Result.Ok

发生这种情况是因为 printf 和类似的方法使用格式。它允许以类型安全的方式使用这些方法。例如 printfn "%d" 强制整数作为参数

printfn "%d" 3
printfn "%d" 3.14 // error

printfn "%s %f" 强制执行字符串和浮点数。

printfn "%s %f" "Hello" 3.14
printfn "%s %f" '3' 14 // error

这意味着你应该这样改变方法(添加"%s"

member this.Trace format = Printf.kprintf (fun s -> if not quiet then logger.Trace(s)) "%s" format