I have this code
let my_fun: [`X | `Y | `Z] -> [`Z | `Y] = function
| `X -> `Y
| x -> x
It won't compile with message
11 | | x -> x
^
Error: This expression has type [ `X | `Y | `Z ]
but an expression was expected of type [ `Y | `Z ]
The second variant type does not allow tag(s) `X
Why can't the complire infer the type [ if it is clear that `X can be never returned from the function?Z |Y]
A simpler example is:
The compiler has to reject it because typing in ML languages requires that both branches have the same type 1, and types
intandstringcannot be unified; this is true even though you could say that there is no chance the expression could ever evaluate to 0 (keep in mind however that formally speaking, it makes no sense to say we evaluate an expression that is not part of the language as defined).In a
matchexpression, the types of the left part of all clauses must unify to the type of the expression being matched. Soxin the last clause has the same type as the implicit argument infunction, which is the input type declared in the signature. This is true whether or not`Xis a valid value in that context.You need to enumerate all the cases that are valid; if you need this often in your code then you'd better write a dedicated function for that:
For example:
See also Set-Theoretic Types for Polymorphic Variants (pdf)
[1] For comparison, in Common Lisp, which is dynamically typed, the equivalent expression is valid; a static analysis as done by SBCL's compiler can infer its type, i.e. a string of length 5: