Подавите исчерпывающее предупреждение соответствия в 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: это сопоставление с образцом не является исчерпывающим. Вот пример значения, которое не подобрано: (ПЛАВАЙТЕ _ |INT _ |UNSET),

Как я, как предполагается, решаю этот вид проблем?Заранее спасибо

10
задан Pascal Cuoq 25 June 2010 в 23:06
поделиться

4 ответа

Эту проблему можно решить, используя полиморфные варианты 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
8
ответ дан 3 December 2019 в 22:34
поделиться

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
0
ответ дан 3 December 2019 в 22:34
поделиться

Взгляните на этот и выполните поиск по запросу «отключить предупреждения». Вы должны подойти к флагу -w .

Если вы хотите исправить это методом «окамлиша», то я думаю, вы должны сделать сопоставление с шаблоном исчерпывающим, то есть охватить все возможные случаи.

Но если вы не хотите сравнивать все возможные значения, вы можете рассмотреть возможность использования подстановочного знака (см. здесь ), который охватывает все случаи, которые вы не хотите обрабатывать явно.

4
ответ дан 3 December 2019 в 22:34
поделиться

В этом конкретном случае полиморфные варианты, как объяснил Паскаль, являются хорошим ответом.

Иногда, однако, вы сталкиваетесь с невозможным случаем. Тогда я считаю естественным написать

(fun s -> match Array.get var_values i with
            | BOOL v -> v
            | _ -> assert false)

Это гораздо лучше, чем использовать флаг -w p, который может скрыть другие, нежелательные неисчерпывающие совпадения шаблонов.

3
ответ дан 3 December 2019 в 22:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: