如何定义在F#printfn相当于(How to define printfn equivalent

2019-06-24 01:07发布

因为我做的研究与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(...)作为变通,但问题仍然是understading F#的类型系统有趣。

Answer 1:

您可以使用kprintf功能,其格式使用标准语法的字符串,但随后调用(lambda)函数指定要打印的格式化字符串。

例如,下面的打印,如果该字符串debug设置否则什么也不做:

let myprintf fmt = Printf.kprintf (fun str -> 
  // Output the formatted string if 'debug', otherwise do nothing
  if debug then printfn "%s" str) fmt


Answer 2:

我一直在剖析我的应用程序,发现调试格式导致显著的性能问题 。 调试格式的代码几乎每一个串上出现,由于应用程序的性质。
显然,这已经被造成kprintf无条件地格式化,然后通过一个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


文章来源: How to define printfn equivalent in F#