F#で識別された共用体の可能な「値」をどのように列挙できますか?
Enum.GetValues(Type)
識別された共用体のようなものがあるかどうかを知りたいのですが、どのような種類のデータを列挙するかはわかりません。オプションごとに1つの項目を含む、識別された共用体のリストまたは配列を生成したいと思います。
F#で識別された共用体の可能な「値」をどのように列挙できますか?
Enum.GetValues(Type)
識別された共用体のようなものがあるかどうかを知りたいのですが、どのような種類のデータを列挙するかはわかりません。オプションごとに1つの項目を含む、識別された共用体のリストまたは配列を生成したいと思います。
はい、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の場合、次のようになります(出力を少し簡略化しました)。
type Microsoft.FSharp.Core.FSharpOption`1[System.Int32] =
| None
| Some of System.Int32
この情報には多くの興味深い用途があります。たとえば、F#ユニオンからDBスキーマを生成したり、XMLを識別されたユニオン(構造を記述する)に解析する関数を作成したりできます。今年初めのGOTOカンファレンスでXML処理のサンプルについて話しました。
識別された共用体が単純な識別子のみで構成されている場合(データを格納する場合はありません。これが必要な場合があります:要点
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
この場合、成功またはエラーのために配列に含めるものを除いて何をしますか?