Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I customize output of a custom type using printf?

I've read through a good chunk of Expert F# and am working on building an actual application. While debugging, I've grown accustomed to passing fsi commands like this to make things legible in the repl window:

fsi.AddPrinter(fun (x : myType) -> myType.ToString()) 

I would like to extend this to work with the printf formatter, so I could type e.g.

printf "%A" instanceOfMyType  

and control the output for a custom type. The book implies that this can be done (p 93, "Generic structural formatting can be extended to work with any user-defined data types, a topic covered on the F# website"), but I have failed to find any references as to how to actually accomplish this. Does anyone know how? Is it even possible?

Edit:

I should have included a code sample, it's a record type that I'm dealing with, e.g.

type myType =      {a: int}             override m.ToString() = "hello"  let t = {a=5} printfn "%A" t printfn "%A" (box t)   

both print statements yield:

{a = 5;} 
like image 500
flatline Avatar asked Apr 26 '09 22:04

flatline


People also ask

How do you print %% in printf?

Generally, printf() function is used to print the text along with the values. If you want to print % as a string or text, you will have to use '%%'.

How do you format numerical output with printf?

The printf and format Methodsout. format("The value of " + "the float variable is " + "%f, while the value of the " + "integer variable is %d, " + "and the string is %s", floatVar, intVar, stringVar);

What is formatted output using printf () statement explain it?

One, the printf (short for "print formatted") function, writes output to the computer monitor. The other, fprintf, writes output to a computer file. They work in almost exactly the same way, so learning how printf works will give you (almost) all the information you need to use fprintf.

Can we use %d in printf?

In C programming language, %d and %i are format specifiers as where %d specifies the type of variable as decimal and %i specifies the type as integer. In usage terms, there is no difference in printf() function output while printing a number using %d or %i but using scanf the difference occurs.


2 Answers

It looks like the Right Way to do this in F# 2.0 is by using the StructuredFormatDisplay attribute, for example:

[<StructuredFormatDisplay("hello {a}")>] type myType = {a: int} 

In this example, instead of the default {a = 42;}, you would get hello 42.

This works the same way for object, record, and union types. And although the pattern must be of the format "PreText {PropertyName} PostText" (PreText and PostText being optional), this is actually more powerful than ToString() because:

  1. PropertyName can be a property of any type. If it is not a string, then it will also be subject to structured formatting. Don Syme's blog gives an example of recursively formatting a tree in this way.

  2. It may be a calculated property. So you could actually get ToString() to work for record and union types, though in a rather round-about way:

    [<StructuredFormatDisplay("{AsString}")>] type myType =      {a: int}     override m.ToString() = "hello"     member m.AsString = m.ToString()  // a property that calls a method 

By the way, ToString() will always be used (even for record and union types) if you call printfn "%O" instead of printfn "%A".

like image 50
Todd Owen Avatar answered Sep 20 '22 22:09

Todd Owen


Hmm... I vaguely recall some changes to this, but I forget if they happened before or after the CTP (1.9.6.2).

In any case, on the CTP, I see that

type MyType() =     override this.ToString() = "hi" let x = new MyType() let xs = Array.create 25 x printfn "%A" x printfn "%A" xs 

when evaluated in the VFSI window does what I would want, and that

x;; xs;; 

also prints nicely. So, I guess I am unclear how this differs from what is desired?

like image 41
Brian Avatar answered Sep 16 '22 22:09

Brian