7

由于我使用 F# 进行研究(特别是使用 F# 交互),我希望有可切换的“调试时打印”功能。

我可以

let dprintfn = printfn

F# 互动 说

val dprintfn : (Printf.TextWriterFormat<'a> -> 'a)

我可以使用

dprintfn "myval1 = %d, other val = %A" a b

每当我想在我的脚本中。

现在我想定义dprintfn不同的,这样它会忽略它的所有参数,但语法兼容printfn. 如何?


我想到的最接近(但不起作用)的变体是:

let dprintfn (arg: (Printf.TextWriterFormat<'a> -> 'a)) = ()

但是它下面的内容没有编译dprintfn "%A" "Hello",导致error FS0003: This value is not a function and cannot be applied.

PS我目前使用别名Debug.WriteLine(...)作为解决方法,但是对于理解 F# 的类型系统,这个问题仍然很有趣。

4

2 回答 2

11

您可以使用该kprintf函数,它使用标准语法格式化字符串,然后调用您指定的 (lambda) 函数来打印格式化的字符串。

例如,以下内容打印字符串 ifdebug已设置,否则不执行任何操作:

let myprintf fmt = Printf.kprintf (fun str -> 
  // Output the formatted string if 'debug', otherwise do nothing
  if debug then printfn "%s" str) fmt
于 2012-04-28T17:26:55.507 回答
3

我一直在分析我的应用程序,发现调试格式会导致严重的性能问题。由于应用程序的性质,调试格式几乎出现在代码的每个字符串上。
显然,这是由kprintf无条件格式化然后将 a 传递string给谓词造成的。
最后,我想出了以下可能对您有用的解决方案:

let myprintf (format: Printf.StringFormat<_>) arg =
    #if DEBUG 
        sprintf format arg
    #else
        String.Empty
    #endif

let myprintfn (format: Printf.TextWriterFormat<_>) arg =
    #if DEBUG
        printfn format arg
    #else
        ()
    #endif

用法很简单,格式检查也很好:

let foo1 = myprintf "foo %d bar" 5
let foo2 = myprintf "foo %f bar" 5.0

// can't accept int
let doesNotCompile1 = myprintf "foo %f bar" 5
// can't accept two arguments
let doesNotCompile2 = myprintf "foo %f bar" 5.0 10

// compiles; result type is int -> string
let bar = myprintf "foo %f %d bar" 5.0
于 2012-07-05T21:49:47.707 回答