Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
535 views
in Technique[技术] by (71.8m points)

f# - 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;}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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".


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...