Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define printfn equivalent in F#

Since I do research with F# (in particular, using F# interactive), I'd like to have switchable "print-when-in-debug" function.

I can do

let dprintfn = printfn

F# interactive says

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

and I can use

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

whenever I want in my scripts.

Now I'd like to define dprintfn differently, so that it would ignore all its arguments yet being syntax-compatible with printfn. How?


The closest (yet non-working) variant I have in mind is:

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

but it the following doesn't compile then dprintfn "%A" "Hello", resulting in error FS0003: This value is not a function and cannot be applied.

P.S. I currently use an alias for Debug.WriteLine(...) as work-around, but the question is still interesting for understading F#'s type system.

like image 800
bohdan_trotsenko Avatar asked Apr 28 '12 17:04

bohdan_trotsenko


People also ask

What does %f represent with printf?

The f in printf stands for formatted, its used for printing with formatted output.

Is %F for double?

"%f" is the (or at least one) correct format for a double. There is no format for a float , because if you attempt to pass a float to printf , it'll be promoted to double before printf receives it1.

How do I use the F function in print?

The printf() is a library function to send formatted output to the screen. The function prints the string inside quotations. To use printf() in our program, we need to include stdio.h header file using the #include <stdio.h> statement.

How do printf ()' s format specifiers %E and %f?

%g and %G are simplifiers of the scientific notation floats %e and %E. %g will take a number that could be represented as %f (a simple float or double) or %e (scientific notation) and return it as the shorter of the two. The output of your print statement will depend on the value of sum.


2 Answers

You can use the kprintf function, which formats a string using the standard syntax, but then calls a (lambda) function you specify to print the formatted string.

For example, the following prints the string if debug is set and otherwise does nothing:

let myprintf fmt = Printf.kprintf (fun str -> 
  // Output the formatted string if 'debug', otherwise do nothing
  if debug then printfn "%s" str) fmt
like image 100
Tomas Petricek Avatar answered Sep 19 '22 12:09

Tomas Petricek


I've been profiling my application and found that debug formatting causes significant performance issues. Debug formatting occurs on almost every string of the code, due to the nature of the application.
Obviously, this has been caused by kprintf which unconditionally formats and then passes a string to a predicate.
Finally, I came up with the following solution that may be useful for you:

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

Usage is quite simple, and format checking works fine:

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
like image 34
bytebuster Avatar answered Sep 20 '22 12:09

bytebuster