mic*_*lpm 31 f# discriminated-union
如何通过F#中歧视联盟的可能"价值"进行枚举?
我想知道是否有类似于Enum.GetValues(Type)受歧视的工会的事情,我很难确定我会列举什么样的数据.我想为每个选项生成一个具有区别联合的列表或数组,其中包含一个项目.
Rob*_*ert 37
是的,F#在.NET的反射之上构建了自己的反射层,以帮助您理解特定于F#的类型,例如区分联合.这是允许您枚举联合案例的代码:
open Microsoft.FSharp.Reflection
type MyDU =
| One
| Two
| Three
let cases = FSharpType.GetUnionCases typeof<MyDU>
for case in cases do printfn "%s" case.Name
Run Code Online (Sandbox Code Playgroud)
稍微扩展Robert的示例 - 即使您没有受歧视联合的实例,也可以使用F#反射来获取有关类型的信息(例如各个案例的参数类型).以下扩展了Robert的示例,它还打印了参数的类型:
open Microsoft.FSharp.Reflection
let ty = typeof<option<int>>
let cases = FSharpType.GetUnionCases ty
printfn "type %s =" ty.FullName
for case in cases do
printf "| %s" case.Name
let fields = case.GetFields()
if fields.Length > 0 then
printf " of"
for fld in fields do
printf " %s " fld.PropertyType.FullName
printfn ""
Run Code Online (Sandbox Code Playgroud)
例如,对于option<int>type,你会得到(我稍微简化了输出):
type Microsoft.FSharp.Core.FSharpOption`1[System.Int32] =
| None
| Some of System.Int32
Run Code Online (Sandbox Code Playgroud)
这些信息有许多有趣的用途 - 例如,您可以从F#联合生成DB模式,或者创建将XML解析为区别联合(描述结构)的函数.我在今年早些时候的GOTO会议上谈到了XML处理示例.
如果你的歧视联盟只是由普通标识符组成(没有案例存储任何数据,这可能就是你需要的:gist
open Microsoft.FSharp.Reflection
module SimpleUnionCaseInfoReflection =
// will crash if 'T contains members which aren't only tags
let Construct<'T> (caseInfo: UnionCaseInfo) = FSharpValue.MakeUnion(caseInfo, [||]) :?> 'T
let GetUnionCaseInfoAndInstance<'T> (caseInfo: UnionCaseInfo) = (caseInfo, Construct<'T> caseInfo)
let AllCases<'T> =
FSharpType.GetUnionCases(typeof<'T>)
|> Seq.map GetUnionCaseInfoAndInstance<'T>
Run Code Online (Sandbox Code Playgroud)
#load "SimpleUnionCaseInfoReflection.fs"
type Foos = Foo | Bar | Baz
SimpleUnionCaseInfoReflection.AllCases<Foos> |> Seq.iter (fun (caseInfo, instance) ->printfn "name: %s instance: %O is Bar? : %b" caseInfo.Name instance (instance.Equals(Foos.Bar)))
(*
> name: Foo instance: FSI_0055+Foos is Bar? : false
> name: Bar instance: FSI_0055+Foos is Bar? : true
> name: Baz instance: FSI_0055+Foos is Bar? : false
*)
Run Code Online (Sandbox Code Playgroud)