MiP
MiP

Reputation: 6442

Pretty print discriminated unions

I have an Option type:

type Option<'a> =
    | Some of value:'a
    | None

type MyString = string

// Syntax
type type-name =
    | case-identifier1 [of [ fieldname1 : ] type1 [ * [ fieldname2 : ] type2 ...]
    | case-identifier2 [of [ fieldname3 : ] type3 [ * [ fieldname4 : ] type4 ...]
...

I want to print something with a format like this:

"type-name: case-identifier(fieldname1:type1:'value1', fieldname2:type2:'value2')"

// Example:
let a : Option<MyString> = Some "1"
print a -> "Option: Some(value:MyString:'1')"
let b = None
print b -> "Option: None"

I've asked a similar question before, but I still can't get the type-name and type of the field.

Upvotes: 1

Views: 127

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243096

In your example, you will not be able to print MyString, because this is a type alias and type aliases do not have any representation in the compiled code (only in some additional F# meta-data, but that does not help here). So, in the compiled code, the runtime just sees string. I'm going to use a single-case DU instead:

type Option<'a> =
    | Some of value:'a
    | None

type MyString = 
    | MyString of string
    override x.ToString() = let (MyString s) = x in s

let a = Some (MyString "1")
let b = None

A function that formats the DU values according to your example looks something like this:

open Microsoft.FSharp.Reflection

let formatUnion<'T> (value:'T) =
    let case, args = FSharpValue.GetUnionFields(value, typeof<'T>)
    let args = 
        [| for f, v in Seq.zip (case.GetFields()) args ->
             sprintf "%s:%s='%O'" f.Name  f.PropertyType.Name v |]
    sprintf "%s: %s(%s)" (typeof<'T>.Name) case.Name (String.concat "," args)

This prints "Option'1: Some(value:MyString='1')" - aside from the backtick-one that is there because the type Option is generic, this looks like the thing you wanted - I did not do anything clever to handle nested types, so that's one thing you'll still need to add.

Upvotes: 3

Related Questions