One of the things you will most likely need to do when you work with any language is format text, and surprise surprise F# is no different.
Since F# is a .NET language we can always make use of Console.WriteLine(..)
and String.Format(..)
where we could use any of the regular formatters that you have used in your regular .NET code.
However F# also supports a more C syntax like technique which is available within the Core.Printf
module. One function within that can be used instead of the Console.WriteLine(..)
.NET class usage.
The F# equivalent function that you would use to write to the standard output is printfn
, which is actually the preferred method when dealing with text formatting in F#.
Why is printfn preferred over Console.WriteLine(..) ?
There are several reasons that printfn
is preferred, some of the main reasons are shown below:
- Static type checking. Which means if we pass an
int
value where a string
is expected, we are warned about this - As
printfn
is a native F# function, is acts just like any other F# function. Where you do certain F# things, such as possibly partially applying the function (which is something we will try and cover a bit more in a subsequent post) - It will have baked in support for standard F# types
Lets just spend a bit more time on the statically typed point above. Consider the following code snippets
printfn "should be a decimal value %d" "cat"
printfn "should be a decimal value %d" 42
Console.WriteLine("should be a decimal value {0}" , "cat")
printfn "this only expected 1 arg of type decimal %d" 42 "dog"
Console.WriteLine("this only expected 1 arg of type decimal {0}" , 42, "dog")
printfn "this only expected 2 args of type decimal %d and string %s" 42 "dog"
If we now look at a screen shot of this code actually in the Visual Studio IDE, we can indeed see that the lines that we expected to fail are clearly shown as being in error:
How we use printfn?
So now that we know why we should use printfn
, how do we use it?
Well probably the best place to start is by looking at some of the standard formatters available when dealing with values. The following table illustrates the standard operators that are available to you:
I have taken these directly from MSDN : http://msdn.microsoft.com/en-us/library/ee370560.aspx
Type | Description |
%b | Formats a bool, formatted as true or false. |
%c | Formats a character. |
%s | Formats a string, formatted as its contents, without interpreting any escape characters. |
%d, %i | Formats any basic integer type formatted as a decimal integer, signed if the basic integer type is signed. |
%u | Formats any basic integer type formatted as an unsigned decimal integer. |
%x | Formats any basic integer type formatted as an unsigned hexadecimal integer, using lowercase letters a through f. |
%X | Formats any basic integer type formatted as an unsigned hexadecimal integer, using uppercase letters A through F. |
%o | Formats any basic integer type formatted as an unsigned octal integer. |
%e, %E, %f, %F, %g, %G | Formats any basic floating point type (float, float32) formatted using a C-style floating point format specifications. |
%e, %E | Formats a signed value having the form [-]d.dddde[sign]ddd where d is a single decimal digit, dddd is one or more decimal digits, ddd is exactly three decimal digits, and sign is + or -. |
%f | Formats a signed value having the form [-]dddd.dddd, where dddd is one or more decimal digits. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision. |
%g, %G | Formats a signed value printed in f or e format, whichever is more compact for the given value and precision. |
%M | Formats a Decimal value. |
%O | Formats any value, printed by boxing the object and using its ToString method. |
%A, %+A | Formats any value, printed with the default layout settings. Use %+A to print the structure of discriminated unions with internal and private representations. |
%a | A general format specifier, requires two arguments. The first argument is a function which accepts two arguments: first, a context parameter of the appropriate type for the given formatting function (for example, a TextWriter), and second, a value to print and which either outputs or returns appropriate text.
The second argument is the particular value to print.
|
%t | A general format specifier, requires one argument: a function which accepts a context parameter of the appropriate type for the given formatting function (a TextWriter)and which either outputs or returns appropriate text. Basic integer types are byte, sbyte, int16, uint16, int32, uint32, int64, uint64, nativeint, and unativeint. Basic floating point types are float and float32. |
I would recommend you have a look at that MSDN link, as it contains additional information that may be useful when you need to do some fine grained formatting.
So what about creating nice formatting other than standard out
So we have now seen how to write nicely formatted output to the standard output (printfn
did this), but what about if we wanted to use formatted string in other places? What if we wanted to bind a string value to a nicely formatted string that we constructed using some of the formatters above, or even wanted to write to a StringBuilder
or TextWriter
, does F# enable us to do that easily?
Well yes actually it does, you will find a great many other useful functions in the Core.Printf
module. The full list at time of writing this post was as follows:
Value | Description |
bprintf | Prints to a StringBuilder . |
eprintf | Prints formatted output to stderr . |
eprintfn | Prints formatted output to stderr , adding a newline. |
failwithf | Prints to a string buffer and raises an exception with the given result. Helper printers must return strings. |
fprintf | Prints to a text writer. |
fprintfn | Prints to a text writer, adding a newline. |
kbprintf | Like bprintf , but calls the specified function to generate the result. See kprintf . |
kfprintf | Like fprintf , but calls the specified function to generate the result. See kprintf . |
kprintf | Like printf , but calls the specified function to generate the result. For example, these let the printing force a flush after all output has been entered onto the channel, but not before. |
kspintf | Like sprintf , but calls the specified function to generate the result. See kprintf . |
printf | Prints formatted output to stdout . |
printfn | Prints formatted output to stdout , adding a newline. |
sprintf | Prints to a string by using an internal string buffer and returns the result as a string. Helper printers must return strings. |
I am not going to through all of these but I will go through the most common ones:
bprintf
Prints to a StringBuilder
.
let builder = new StringBuilder(524288)
Printf.bprintf builder "This will be a string line : %s\r\n" "cat"
Printf.bprintf builder "This will be a bool line : %b\r\n" true
Printf.bprintf builder "This will be a int line : %u\r\n" 42
Printf.bprintf builder "This will be a hex line : %X\r\n" 255
printfn "%s" (builder.ToString())
This will give this output in a F# Console Application
fprintf
Prints to a text writer.
use sw = new StreamWriter(@"c:\temp\fprintfFile.txt")
fprintf sw "This is a string line %s\r\n" "cat"
fprintf sw "This is a int line %i" 10
sw.Close()
This will result in a file being created in temp
sprintf
Prints to a string by using an internal string buffer and returns the result as a string. Helper printers must return strings.
let result = Printf.sprintf "This will return a formatted string : %s\r\n" "cat"
printfn "%s" result
This will give this output in a F# Console Application