Подавить исчерпывающее предупреждение о совпадении в OCaml - PullRequest
10 голосов
/ 25 июня 2010

У меня проблема с исправлением предупреждения, которое дает мне компилятор 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)

Как я должен решить такие проблемы?Заранее спасибо

Ответы [ 4 ]

8 голосов
/ 26 июня 2010

Это проблема, которую вы можете решить, используя полиморфные варианты 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
4 голосов
/ 25 июня 2010

Взгляните на this и найдите "отключить предупреждения". Вы должны прийти к флагу -w.

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

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

3 голосов
/ 17 июля 2010

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

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

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

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

0 голосов
/ 25 июня 2010

Упс! Неправильно прочитанный твой вопрос. Оставляя мой ответ ниже для потомков.

Обновленный ответ: есть ли причина, по которой вы выполняете проверку в 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 на совпадение. Или вы можете заменить let на совпадение:

заменить, если / еще:

| 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

заменить пусть:

| 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
...