【发布时间】:2011-10-23 05:58:51
【问题描述】:
如何在 F# 中枚举可区分联合的可能“值”?
我想知道是否有类似Enum.GetValues(Type) 之类的用于受歧视的工会,我不确定我会列举什么样的数据。我想为每个选项生成一个可区分联合的列表或数组。
【问题讨论】:
如何在 F# 中枚举可区分联合的可能“值”?
我想知道是否有类似Enum.GetValues(Type) 之类的用于受歧视的工会,我不确定我会列举什么样的数据。我想为每个选项生成一个可区分联合的列表或数组。
【问题讨论】:
是的,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
【讨论】:
BF.Public ||| BF.NonPublic where BF=System.Reflection.BindingFlags 传递给GetUnionCases。
稍微扩展罗伯特的例子——即使你没有可区分联合的实例,你也可以使用 F# 反射来获取关于 type 的信息(例如 types 个别案例的论点)。以下扩展了 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 ""
例如,对于option<int> 类型,你会得到(我稍微简化了输出):
type Microsoft.FSharp.Core.FSharpOption`1[System.Int32] =
| None
| Some of System.Int32
此信息有许多有趣的用途 - 例如,您可以从 F# 联合生成 DB 模式或创建将 XML 解析为可区分联合(描述结构)的函数。我谈到了XML processing sample at GOTO conference earlier this year。
【讨论】:
如果您的可区分联合仅由普通标识符组成(没有存储任何数据的情况,这可能是您需要的: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>
#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
*)
【讨论】:
如果没有实例,很难看出这如何可能起作用,因为歧视工会可以承载价值。
如果你有这样的类型,例如:
type Status = Success of string | Error of System.Exception | Timeout
在这种情况下,除了您的数组要包含的 Success 或 Error 之外,您还想包含什么?
【讨论】: