Подавить исчерпывающее соответствующее предупреждение в OCaml
У меня возникла проблема с исправлением предупреждения, которое мне предоставляет компилятор 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
Я пытаюсь определить поведение ссылки на переменную внутри логического выражения, так что я делаю
- проверьте, что переменная объявлена
- убедитесь, что переменная имеет тип bool
для этого у меня есть этот код (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: это сопоставление шаблонов не является исчерпывающим. Ниже приведен пример значения, которое не соответствует: (FLOAT _ | INT_ | UNSET)
Как я могу решить такие проблемы? Спасибо заранее
Ответы
Ответ 1
Это проблема, которую вы можете решить с помощью полиморфных вариантов 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
Ответ 2
Посмотрите this и найдите "отключить предупреждения". Вы должны прийти к значку -w
.
Если вы хотите исправить "ocamlish" путь, тогда я думаю, что вы должны сделать соответствие шаблона исчерпывающим, т.е. охватывать все случаи, которые могут произойти.
Но если вы не хотите сопоставлять все возможные значения, вы можете использовать подстановочный знак (см. здесь), который охватывает все которые вы не хотите явно обрабатывать.
Ответ 3
В этом конкретном случае полиморфные варианты, как объясняется Паскалем, являются хорошим ответом.
Иногда, однако, вы застряли в невозможном случае. Тогда я считаю естественным писать
(fun s -> match Array.get var_values i with
| BOOL v -> v
| _ -> assert false)
Это намного лучше, чем использование флага -w p
, который может скрыть другие, нежелательные не исчерпывающие соответствия шаблонов.
Ответ 4
Упс! Не обращай внимания на свой вопрос. Оставляя мой ответ ниже для потомков.
Обновленный ответ: есть ли причина, по которой вы делаете проверку в hashtbl, или почему у вас не могут быть конкретные типы данных (значение типа) в 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 на совпадение. Или вы можете заменить 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