如何枚举 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
稍微扩展 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 ""
例如,对于option<int>
类型,你会得到(我稍微简化了输出):
type Microsoft.FSharp.Core.FSharpOption`1[System.Int32] =
| None
| Some of System.Int32
此信息有许多有趣的用途 - 例如,您可以从 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>
#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 之外,您还需要什么?