subtitulos - ¿Cómo enumerar una unión discriminada en F#?
como enumerar titulos y subtitulos en word (4)
¿Cómo puedo enumerar a través de los posibles "valores" de una unión discriminada en F #?
Quiero saber si hay algo como Enum.GetValues(Type)
para uniones discriminadas, pero no estoy seguro de qué tipo de datos enumeraré. Me gustaría generar una lista o matriz de una unión discriminada con un elemento para cada opción.
Es difícil ver cómo esto podría funcionar sin tener también una instancia, ya que las uniones discriminatorias pueden tener valores.
Si tuvieras un tipo como este por ejemplo:
type Status = Success of string | Error of System.Exception | Timeout
¿Qué incluirías en tu matriz para el éxito o error en este caso?
Para extender ligeramente el ejemplo de Robert, incluso si no tiene una instancia de la unión discriminada, puede usar la reflexión F # para obtener la información sobre el tipo (como los tipos de los argumentos de casos individuales). Lo siguiente amplía el ejemplo de Robert y también imprime los tipos de argumentos:
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 ""
Por ejemplo, para el tipo de option<int>
, obtendrás (simplifiqué ligeramente la salida):
type Microsoft.FSharp.Core.FSharpOption`1[System.Int32] =
| None
| Some of System.Int32
Hay muchos usos interesantes para esta información; por ejemplo, puede generar un esquema de base de datos a partir de uniones F # o crear funciones que analicen XML en una unión discriminada (que describe la estructura). Hablé sobre la muestra de procesamiento XML en la conferencia GOTO a principios de este año .
Sí, F # tiene su propia capa de reflexión construida sobre la reflexión de .NET para ayudarlo a comprender los tipos que son específicos de F #, como discriminar uniones. Aquí está el código que le permitirá enumerar los casos de una unión:
open Microsoft.FSharp.Reflection
type MyDU =
| One
| Two
| Three
let cases = FSharpType.GetUnionCases typeof<MyDU>
for case in cases do printfn "%s" case.Name
Si su unión discriminada solo está formada por identificadores simples (en ningún caso se almacena ningún dato, esto podría ser lo que necesita: 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
*)