Не-литералы OCaml в матче - PullRequest
0 голосов
/ 10 января 2019

Сравнение с не-литеральными значениями

Я в Ocaml (reasonml) могу сопоставить целочисленные значения, например,

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

Однако, скажем, я теперь переключаю свой тип номера на что-то вроде Зарита. Как сопоставить значения, как в приведенном выше?

Есть ли лучший способ, кроме использования | x when x == SomeNumberModule.of_int(0) || x == SomeNumberModule.of_int(1) => ...?

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Типы Zarith являются абстрактными. Одним из следствий этого является то, что их реализация не видна компилятору (вне определяющего их модуля). Следовательно, невозможно сопоставить их с образцом, потому что для этого потребуется взглянуть на внутреннюю структуру абстрактного типа. В зависимости от вашего варианта использования вы можете проецировать тип Zarith на неабстрактный тип и сопоставление с образцом в этой проекции:

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

или если вы используете OCaml с версией ≥ 4.07, можно объединить исключение и любые случаи с шаблоном or:

switch (Z.to_int(x)) {
| 0 | 1 => "small"
| exception Overflow | _ => "large"
}
0 голосов
/ 10 января 2019

Сопоставление с образцом является конструкцией во время компиляции. Компилятор должен знать все возможные значения, чтобы обеспечить исчерпывающую проверку. Он также может очень хорошо оптимизировать эту информацию под рукой.

Вы можете все еще использовать значения времени выполнения с match / switch, как вы обнаружили, но должны использовать when. После этого вы все еще можете использовать шаблоны с литералами до when и значения времени выполнения после, и вы получите исчерпывающую проверку для части шаблона. Но если вы вообще не используете никаких шаблонов, только охранники, может быть, лучше использовать выражение if, поскольку это лучше означает намерение:

if (x == SomeNumberModule.of_int(0) || x == SomeNumberModule.of_int(1)) {
  ...
}
...