У меня есть проблема в фиксации предупреждения, что компилятор OCaml дает мне.
В основном я анализирую выражение, которое может быть составлено Bool
, Int
и Float
.
У меня есть таблица символов, которая отслеживает все символы, объявленные с их типом:
type ast_type = Bool | Int | Float
and variables = (string, int*ast_type) Hashtbl.t;
где int
индекс, используемый позже в массиве всех переменных.
У меня есть затем конкретный тип, представляющий значение в переменной:
type value =
| BOOL of bool
| INT of int
| FLOAT of float
| UNSET
and var_values = value array
Я пытаюсь определить поведение ссылки на переменную в булевом выражении поэтому, что я делаю
чтобы сделать это, у меня есть этот код (s
название переменной):
| GVar s ->
begin
try
let (i,t) = Hashtbl.find variables s in
if (t != Bool) then
raise (SemanticException (BoolExpected,s))
else
(fun s -> let BOOL v = Array.get var_values i in v)
with
Not_found -> raise (SemanticException (VarUndefined,s))
end
Проблема состоит в том, что мои проверки гарантируют что элемент, взятый от var_values
будет иметь тип BOOL of bool
но конечно это ограничение не замечено компилятором, который предупреждает меня:
Предупреждение P: это сопоставление с образцом не является исчерпывающим. Вот пример значения, которое не подобрано: (ПЛАВАЙТЕ _ |INT _ |UNSET),
Как я, как предполагается, решаю этот вид проблем?Заранее спасибо
Эту проблему можно решить, используя полиморфные варианты OCaml.
Вот некоторый компилируемый код OCaml, который, как я предполагаю, демонстрирует вашу проблему:
type ast_type = Bool | Int | Float
and variables = (string, int*ast_type) Hashtbl.t
type value =
| BOOL of bool
| INT of int
| FLOAT of float
| UNSET
and var_values = value array
type expr = GVar of string
type exceptioninfo = BoolExpected | VarUndefined
exception SemanticException of exceptioninfo * string
let variables = Hashtbl.create 13
let var_values = Array.create 13 (BOOL false)
let f e =
match e with
| GVar s ->
begin
try
let (i,t) = Hashtbl.find variables s in
if (t != Bool) then
raise (SemanticException (BoolExpected,s))
else
(fun s -> let BOOL v = Array.get var_values i in v)
with
Not_found -> raise (SemanticException (VarUndefined,s))
end
Он выдает предупреждение:
File "t.ml", line 30, characters 42-48:
Warning P: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
(FLOAT _|INT _|UNSET)
Вот тот же код, преобразованный для использования полиморфных вариантов. Этот код компилируется без предупреждений. Обратите внимание, что полиморфные варианты обладают большей выразительностью, чем стандартные типы (здесь можно выразить, что var_values
- это массив BOOL
), но они могут приводить к озадачивающим предупреждениям.
type ast_type = Bool | Int | Float
and variables = (string, int*ast_type) Hashtbl.t
type value =
[ `BOOL of bool
| `INT of int
| `FLOAT of float
| `UNSET ]
and var_values = value array
type expr = GVar of string
type exceptioninfo = BoolExpected | VarUndefined
exception SemanticException of exceptioninfo * string
let variables = Hashtbl.create 13
let var_values = Array.create 13 (`BOOL false)
let f e =
match e with
| GVar s ->
begin
try
let (i,t) = Hashtbl.find variables s in
if (t != Bool) then
raise (SemanticException (BoolExpected,s))
else
(fun s -> let `BOOL v = Array.get var_values i in v)
with
Not_found -> raise (SemanticException (VarUndefined,s))
end
Вот типы, выведенные OCaml для приведенного выше кода:
type ast_type = Bool | Int | Float
and variables = (string, int * ast_type) Hashtbl.t
type value = [ `BOOL of bool | `FLOAT of float | `INT of int | `UNSET ]
and var_values = value array
type expr = GVar of string
type exceptioninfo = BoolExpected | VarUndefined
exception SemanticException of exceptioninfo * string
val variables : (string, int * ast_type) Hashtbl.t
val var_values : [ `BOOL of bool ] array
val f : expr -> 'a -> bool
Whoops! Неправильно понял ваш вопрос. Оставляю свой ответ ниже для потомков.
Обновленный ответ: есть ли причина, почему вы делаете проверку в hashtbl, или почему вы не можете иметь конкретные типы данных (тип value) в hashtbl? Это бы упростило ситуацию. Как и сейчас, вы можете перенести проверку на bool в Array.get и использовать закрытие:
| GVar s ->
begin
try
let (i,_) = Hashtbl.find variables s in
match (Array.get var_values i) with BOOL(v) -> (fun s -> v)
| _ -> raise (SemanticException (BoolExpected,s))
with
Not_found -> raise (SemanticException (VarUndefined,s))
end
В качестве альтернативы я думаю, что было бы более разумно упростить ваш код. Переместите значения в Hashtbl вместо того, чтобы иметь тип, индекс и массив значений. Или просто храните индекс в Hashtbl и проверяйте тип в массиве.
НЕПРАВИЛЬНЫЙ ОТВЕТ НИЖЕ:
Вы можете заменить if else на match. Или вы можете заменить let на совпадение:
заменить if/else:
| GVar s ->
begin
try
let (i,t) = Hashtbl.find variables s in
match t with Bool -> (fun s -> let BOOL v = Array.get var_values i in v)
| _ -> raise (SemanticException (BoolExpected,s))
with
Not_found -> raise (SemanticException (VarUndefined,s))
end
заменить let:
| GVar s ->
begin
try
match (Hashtbl.find variables s) with (i, Bool) -> (fun s -> let BOOL v = Array.get var_values i in v)
| _ -> raise (SemanticException (BoolExpected,s))
with
Not_found -> raise (SemanticException (VarUndefined,s))
end
Взгляните на этот и выполните поиск по запросу «отключить предупреждения». Вы должны подойти к флагу -w
.
Если вы хотите исправить это методом «окамлиша», то я думаю, вы должны сделать сопоставление с шаблоном исчерпывающим, то есть охватить все возможные случаи.
Но если вы не хотите сравнивать все возможные значения, вы можете рассмотреть возможность использования подстановочного знака (см. здесь ), который охватывает все случаи, которые вы не хотите обрабатывать явно.
В этом конкретном случае полиморфные варианты, как объяснил Паскаль, являются хорошим ответом.
Иногда, однако, вы сталкиваетесь с невозможным случаем. Тогда я считаю естественным написать
(fun s -> match Array.get var_values i with
| BOOL v -> v
| _ -> assert false)
Это гораздо лучше, чем использовать флаг -w p
, который может скрыть другие, нежелательные неисчерпывающие совпадения шаблонов.