3 people like it.

Inverse map for parsing DU cases

Neat trick to improve safety

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
open FSharp.Reflection

type Keyword =
    | FOO
    | BAR
    | BAZ
    | BLAH
    
let inverseMap (print: 'T -> string) (cases: 'T seq) =
    let lookup =
        cases 
        |> Seq.map (fun case -> print case, case)
        |> Map.ofSeq
    
    fun (line: string) -> Map.tryFind line lookup

let cases<'T> =   
    FSharpType.GetUnionCases(typeof<'T>)
    |> Seq.map (fun c -> FSharpValue.MakeUnion(c, Array.empty) :?> 'T)    
        
let matchKeyword: string -> Keyword option =
    inverseMap string cases<Keyword>
    
printfn "%A" (matchKeyword "BAR")
// Some BAR

printfn "%A" (matchKeyword "NOP")
// None
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Reflection
type Keyword =
  | FOO
  | BAR
  | BAZ
  | BLAH
union case Keyword.FOO: Keyword
union case Keyword.BAR: Keyword
union case Keyword.BAZ: Keyword
union case Keyword.BLAH: Keyword
val inverseMap : print:('T -> string) -> cases:seq<'T> -> (string -> 'T option)
val print : ('T -> string)
Multiple items
val string : value:'T -> string

--------------------
type string = System.String
val cases : seq<'T>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
val lookup : Map<string,'T>
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>
val case : 'T
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IReadOnlyDictionary<'Key,'Value>
  interface IReadOnlyCollection<KeyValuePair<'Key,'Value>>
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  ...

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val ofSeq : elements:seq<'Key * 'T> -> Map<'Key,'T> (requires comparison)
val line : string
val tryFind : key:'Key -> table:Map<'Key,'T> -> 'T option (requires comparison)
val cases<'T> : seq<'T>
type FSharpType =
  static member GetExceptionFields : exceptionType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetFunctionElements : functionType:Type -> Type * Type
  static member GetRecordFields : recordType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetTupleElements : tupleType:Type -> Type []
  static member GetUnionCases : unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo []
  static member IsExceptionRepresentation : exceptionType:Type * ?bindingFlags:BindingFlags -> bool
  static member IsFunction : typ:Type -> bool
  static member IsModule : typ:Type -> bool
  static member IsRecord : typ:Type * ?bindingFlags:BindingFlags -> bool
  static member IsTuple : typ:Type -> bool
  ...
static member FSharpType.GetUnionCases : unionType:System.Type * ?allowAccessToPrivateRepresentation:bool -> UnionCaseInfo []
static member FSharpType.GetUnionCases : unionType:System.Type * ?bindingFlags:System.Reflection.BindingFlags -> UnionCaseInfo []
val typeof<'T> : System.Type
val c : UnionCaseInfo
type FSharpValue =
  static member GetExceptionFields : exn:obj * ?bindingFlags:BindingFlags -> obj []
  static member GetRecordField : record:obj * info:PropertyInfo -> obj
  static member GetRecordFields : record:obj * ?bindingFlags:BindingFlags -> obj []
  static member GetTupleField : tuple:obj * index:int -> obj
  static member GetTupleFields : tuple:obj -> obj []
  static member GetUnionFields : value:obj * unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo * obj []
  static member MakeFunction : functionType:Type * implementation:(obj -> obj) -> obj
  static member MakeRecord : recordType:Type * values:obj [] * ?bindingFlags:BindingFlags -> obj
  static member MakeTuple : tupleElements:obj [] * tupleType:Type -> obj
  static member MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?bindingFlags:BindingFlags -> obj
  ...
static member FSharpValue.MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?allowAccessToPrivateRepresentation:bool -> obj
static member FSharpValue.MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?bindingFlags:System.Reflection.BindingFlags -> obj
module Array

from Microsoft.FSharp.Collections
val empty<'T> : 'T []
val matchKeyword : (string -> Keyword option)
type 'T option = Option<'T>
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
Raw view Test code New version

More information

Link:http://fssnip.net/86a
Posted:6 months ago
Author:Evgeniy Andreev
Tags: discriminated unions , parse