0

Match against non-literal values

I in Ocaml (reasonml), I'm able to to match against integer values like,

switch (x) {
| 0 | 1 => "small"
| _ => "large"
}

However, say I now switch my number type to something like Zarith. How do I match against values, like in the above?

Is there a nicer way other than using | x when x == SomeNumberModule.of_int(0) || x == SomeNumberModule.of_int(1) => ...?

glennsl
  • 28,186
  • 12
  • 57
  • 75

2 Answers2

1

Zarith types are abstract. One consequence is that their implementation is not visible by the compiler (outside of the module defining them). Therefore, it is not possible to pattern match on them because this would require to peek at the inner structure of the abstract type. Depending on your use case, you could project the Zarith type to a non-abstract type and pattern match on this projection:

switch (Z.to_int(x)) {
| 0 | 1 => "small"
| exception Overflow => "large"
| _ => "large"
}

or if you are using OCaml with version ≥ 4.07, it is possible to merge the exception and any cases with an or-pattern:

switch (Z.to_int(x)) {
| 0 | 1 => "small"
| exception Overflow | _ => "large"
}
octachron
  • 17,178
  • 2
  • 16
  • 23
  • Yeah, that makes sense about the compiler not knowing about Zarith types at compile time. Shame we can't look at the type in a switch case, like in Swift. For my use-cases, this example works really well, I'll give it a shot! Thanks! – Jacob Parker Jan 10 '19 at 17:01
0

Pattern matching is a compile-time construct. The compiler needs to know all the possible values in order to provide exhaustiveness checking. It can also optimize it really well with all that information at hand.

You can still use runtime values with match/switch, as you have discovered, but have to use when. You can then still use patterns with literals before when and runtime values after, and will get exhaustiveness checking for the pattern part of it. But if you don't use any patterns at all, just guards, it might be better to use an if expression since that better signifies the intent:

if (x == SomeNumberModule.of_int(0) || x == SomeNumberModule.of_int(1)) {
  ...
}
glennsl
  • 28,186
  • 12
  • 57
  • 75
  • So this might get slightly off topic, but why is the exhaustiveness not the same when using integers and another basically infinite-option value type? – Jacob Parker Jan 10 '19 at 11:36
  • How do you mean it's not the same? – glennsl Jan 10 '19 at 11:38
  • I don't really understand why matching can't be done for arbitrary values, especially when those values are constant. Is it me not understanding the ocaml concepts fully, or is it just one of those things that hasn't been implemented? – Jacob Parker Jan 10 '19 at 11:43
  • 1
    But they're not constant. `SomeNumberModule.of_int(0)` is not a constant expression. It's not evaluated at compile time. It might not even be pure, but could return a random value at runtime. – glennsl Jan 10 '19 at 11:57