I have the following code:
type Message<\'a> = | Message of \'a
let handleMessage message =
match box message with
| :? Message<_> ->
Whenever you see _ as a type parameter, think of it as a fresh type parameter that you don't care about. If we tweak your first definition accordingly:
let handleMessage message =
match box message with
| :? Message<'_a> -> printfn "Message"
| _ -> printfn "Not message"
then the compiler gives us this helpful clue:
warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable '_a has been constrained to be type 'obj'.
The problem is that the type parameter has to be given some specific value, but the compiler has no basis on which to pick one so it defaults to obj, which is not what you want.
There's no great way to do this out of the box, but you can create an active pattern to simplify the experience somewhat: https://stackoverflow.com/a/2140485/82959.