2017-05-26 90 views
1

我有一個Option類型:漂亮的打印識別聯合

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

我要打印的東西,像這樣的格式:

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

我問過一個similar question之前,但我仍然可以沒有獲得字段的類型名稱和類型。

回答

3

在您的示例中,您將無法打印MyString,因爲這是一個類型別名,並且類型別名在編譯的代碼中沒有任何表示(僅在某些其他F#元數據中,但這並不能幫助這裏)。所以,在編譯的代碼中,運行時只能看到string。我將使用一個單例DU代替:

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 

是格式化DU值根據你的例子看起來是這樣的一個功能:

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) 

這將打印"Option'1: Some(value:MyString='1')" - 除了從因爲類型Option是通用的,所以這裏看起來像你想要的東西 - 我沒有做任何聰明的事情來處理嵌套類型,所以這是你仍然需要添加的一件事。