How to manage debug printing in F #

I want to add debug printing to my project with a function that has a type signature, like:

bool -> Printf.TextWriterFormat<'a> -> 'a

i.e. he should take the bool, indicating whether we are in difficult mode, and use this to decide whether to print or not.

For example, let's say dprint : bool -> Printf.TextWriterFormat<'a> -> 'a, then I would like to:

> dprint true "Hello I'm %d" 52;;
Hello I'm 52
val it : unit = ()
> dprint false "Hello I'm %d" 52;;
val it : unit = ()

The idea is that a command line flag can be used to avoid control of this output. I also want to avoid the overhead in the "illogical" case. You can define a function that works like this using kprintf:

let dprint (v: bool) (fmt: Printf.StringFormat<'a,unit>) =  
  let printVerbose (s: string) =
    if v then System.Console.WriteLine(s)

  fmt |> Printf.kprintf printVerbose

but printing / ignoring a sequence of numbers with List.iter (dprint b "%A") [1..10000](b \ in {true, false}) takes 1.5 s for both b values ​​on my machine.

, , , :

let dprint (v: bool) (fmt: Printf.TextWriterFormat<'a>) : 'a =
  let rec mkKn (ty: System.Type) =
    if FSharpType.IsFunction(ty) then
      let _, ran = FSharpType.GetFunctionElements(ty)
      FSharpValue.MakeFunction(ty,(fun _ -> mkKn ran))
    else
      box ()
  if v then
    printfn fmt
  else
    unbox<'a> (mkKn typeof<'a>)

( , , printf).

, :

if !Options.verbose then
    printfn "Debug important value: %A" bigObject5

:

dprint (fun () -> printfn "Debug important value: %A" bigObject5)

, - ?

+5
3

, . , ? :

let rec mkKn (ty: System.Type) =
    if Reflection.FSharpType.IsFunction(ty) then
        let _, ran = Reflection.FSharpType.GetFunctionElements(ty)
        // NOTICE: do not delay `mkKn` invocation until runtime
        let f = mkKn ran
        Reflection.FSharpValue.MakeFunction(ty, fun _ -> f)
    else
        box ()

[<Sealed>]
type Format<'T> private () =
    static let instance : 'T =
        unbox (mkKn typeof<'T>)
    static member Instance = instance

let inline dprint verbose args =
    if verbose then
        printfn args
    else
        Format<_>.Instance

# . Printf - , , . F # .

#time List.iter (dprint false "%A") [1..10000]:

  • : 0.85
  • : 0.27
  • : 0.03
+5

:

/// Prints a formatted string to DebugListeners.
let inline dprintfn fmt =
    Printf.ksprintf System.Diagnostics.Debug.WriteLine fmt

:

dprintfn "%s %s" "Hello" "World!"

Debug.WriteLine(...) [<Conditional("DEBUG")>], F # ( IL, , .

, , . , .

UPDATE: ( ), F # 2.0 ( ), , . , , , .

+2

Why not use #definesjust do

let dprint  (fmt: Printf.StringFormat<'a,unit>) =  
#if DEBUG
  let printVerbose (s: string) =
        System.Console.WriteLine(s)

  fmt |> Printf.kprintf printVerbose
#else
   fun _ -> ()

On my machine, the test sample takes 0.002 s in the optimized version

+1
source

All Articles