The main question is why type
let pp= function | `A -> "A" | `B -> "B" | _ -> "?"
output as [> `A| `B] -> string [> `A| `B] -> string , not like [< `A| `B | ... ] -> string [< `A| `B | ... ] -> string [< `A| `B | ... ] -> string (where ... stands for any constructor). The answer is that this is a design choice and a compromise between false positive and false negative: https://www.math.nagoya-u.ac.jp/~garrigue/papers/matching.pdf .
More precisely, the second type was considered too weak, since it was too easy to lose information that `A `B were present in pp . For example, consider the following code, where `B is a spelling error and should `B :
let restrict (`A | `b) = () let dual x = restrict x, pp x
This code does not currently work with
Error: This expression is of type [<`A | `b], but an expression like [>` A | `B]
The first type of option does not allow the use of the `B tag
At this point, if `B was a spelling mistake, you can catch the mistake here. If pp were printed [< `A|`B |..] , the type of the double would be limited to [`A] -> unit * string without any chance of catching this error. Moreover, with the current character set, if `B not a spelling error, it is entirely possible to make dual valid by adding some coercion
let dual x = restrict x, pp (x:[`A]:>[>`A]);; (* or *) let dual x = restrict x, (pp:>[`A] -> _) x
makes it very clear that restrict and pp work with different sets of polymorphic variants.
source share