如何列举F#中的歧视联盟?

时间:2011-08-09 13:42:14

标签: f# discriminated-union

如何枚举F#中受歧视联盟的可能“价值”?

我想知道对于受歧视的工会是否有类似Enum.GetValues(Type)的东西,我很难确定我会列举哪种数据。我想为每个选项生成一个带有区别联合的列表或数组,其中包含一个项目。

4 个答案:

答案 0 :(得分:36)

是的,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

答案 1 :(得分:9)

稍微扩展Robert的示例 - 即使您没有受歧视联合的实例,也可以使用F#反射来获取有关类型的信息(例如 types < / em>个案的论据)。以下扩展了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#联合生成数据库模式,或创建将XML解析为区分联合(描述结构)的函数。我谈到了XML processing sample at GOTO conference earlier this year

答案 2 :(得分:6)

如果您的歧视联盟仅由普通标识符组成(不存储任何数据,则可能是您需要的: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
*)

答案 3 :(得分:2)

由于歧视联盟可以携带价值观,因此很难看出如果没有实例,这可能会如何发挥作用。

如果你有类似这样的类型:

type Status = Success of string | Error of System.Exception | Timeout

除了你的数组在这种情况下包含成功或错误之外你会怎样?