Skip to content

Instantly share code, notes, and snippets.

@medigor
Created April 10, 2020 15:12
Show Gist options
  • Save medigor/15e5a5a2f9fd01f29cd80a1bdda315c2 to your computer and use it in GitHub Desktop.
Save medigor/15e5a5a2f9fd01f29cd80a1bdda315c2 to your computer and use it in GitHub Desktop.
open System
open System.Collections.Concurrent
open Microsoft.FSharp.Reflection
open Microsoft.FSharp.Quotations.Patterns
type UnionUtils =
static member private isTypeUnionCache = ConcurrentDictionary<Type, bool>()
static member private tagGetterCache = ConcurrentDictionary<Type, obj -> int>()
static member private getUnionCaseInfo expr =
match expr with
| Lambda(_, expr) -> UnionUtils.getUnionCaseInfo expr
| Let(_, _, expr) -> UnionUtils.getUnionCaseInfo expr
| NewUnionCase(unionCaseInfo, _) -> unionCaseInfo
| _ -> failwith "no way"
static member private IsSameCase<'a>(x: 'a, unionCaseInfo: UnionCaseInfo) =
let t = typeof<'a>
let isUnion = UnionUtils.isTypeUnionCache.GetOrAdd(t, FSharpType.IsUnion)
if not isUnion then failwithf "Type %s is not union!" t.Name
let getTag = UnionUtils.tagGetterCache.GetOrAdd(key = t, valueFactory = Func<_,_>(fun _ ->
let m = t.GetProperty("Tag").GetGetMethod()
fun o -> m.Invoke(o, null) :?> int
))
getTag x = unionCaseInfo.Tag
static member IsSameCase<'a>(x: 'a, y: Quotations.Expr<'a>) =
UnionUtils.IsSameCase(x, UnionUtils.getUnionCaseInfo y)
static member IsSameCase<'a,'b>(x: 'a, y: Quotations.Expr<'b -> 'a>) =
UnionUtils.IsSameCase(x, UnionUtils.getUnionCaseInfo y)
type Foo =
| A of string * int
| B
UnionUtils.IsSameCase(B, <@A@>) |> printfn "%b"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment