Skip to content

Instantly share code, notes, and snippets.

@Szer
Last active April 10, 2020 15:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Szer/23afcf143cbdcc09aae17a7159136fc2 to your computer and use it in GitHub Desktop.
Save Szer/23afcf143cbdcc09aae17a7159136fc2 to your computer and use it in GitHub Desktop.
Concise check if cases of DU are the same
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@>)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment