2010-06-25 11 views
10

Tengo un problema para solucionar una advertencia que el compilador OCaml me proporciona.Suprime la advertencia de coincidencia exhaustiva en OCaml

Básicamente estoy analizando una expresión que puede estar compuesta por Bool, Int y Float.

I tienen una tabla de símbolos que rastrea todos los símbolos declaradas con su tipo:

type ast_type = Bool | Int | Float 
and variables = (string, int*ast_type) Hashtbl.t; 

donde int es el índice utilizado más adelante en el conjunto de todas las variables.

que tienen entonces un tipo concreto que representa el valor de una variable:

type value = 
    | BOOL of bool 
    | INT of int 
    | FLOAT of float 
    | UNSET 
and var_values = value array 

Estoy tratando de definir el comportamiento de una referencia variable dentro de una expresión booleana así que lo que hago es

  • comprobación de que la variable está declarada
  • comprobación de que la variable es de tipo bool

hacer esto tengo este código (s es el nombre de la variable):

| 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 

El problema es que mis cheques aseguran que el elemento tomado de var_values será de tipo BOOL of bool pero por supuesto esta restricción ISN' t visto por el compilador que me avisa:

Advertencia P: esta coincidencia de patrón no es exhaustiva. Aquí es un ejemplo de un valor que no es igualada: (FLOAT _ | _ INT | DESACTIVADO)

¿Cómo se supone que voy a resolver este tipo de problemas? Gracias de antemano

+0

Como nota aparte, solo es útil declarar el tipo 'var_values ​​= value array' si tiene la intención de abstraerlo y dejar solo su nombre visible desde fuera del módulo. Además de esta posibilidad, es un alias de tipo inútil que puede hacer que los mensajes de error sean menos legibles. –

Respuesta

8

Este es un problema que se puede resolver utilizando OCaml's polymorphic variants.

Aquí hay un código OCaml compilables que deduzco exhibe su problema:

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 

Se genera la advertencia:

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) 

Aquí es el mismo código transformado a utilizar variantes polimórficas. Ese código compila sin advertencias. Tenga en cuenta que las variantes polimórficas tienen más poder expresivo que los tipos estándar (lo que permite expresar que var_values es una matriz de BOOL solamente), pero pueden dar lugar a advertencias desconcertantes.

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 

Éstos son los tipos inferidos por OCaml en el código anterior:

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

Eche un vistazo a this y busque "deshabilitar advertencias". Deberías ponerte en una bandera -w.

Si quiere arreglarlo de la forma "ocamlish", entonces creo que debe hacer que el patrón sea igual de exhaustivo, es decir, cubrir todos los casos que puedan ocurrir.

Pero si no desea hacer coincidir todos los valores posibles, puede considerar el uso de comodines (consulte here), que cubren todos los casos que no desea manejar explícitamente.

+0

Sí, esto puede ayudar, pero ¿hay alguna forma de corregir la advertencia de una manera segura y sin deshabilitarla? – Jack

+2

@Jack El método True OCamlish es construir el tipo de datos para que no haya ningún valor posible sin usar. Pero eso no siempre es práctico o deseable. El segundo sería agregar un patrón de comodín final ('_') que genere una excepción (ya sea' Invalid_argument' o una alternativa específica del módulo). –

0

¡Vaya! Leyó mal su pregunta. Dejando mi respuesta a continuación para la posteridad.

Respuesta actualizada: ¿hay alguna razón por la que está haciendo el control en el hashtbl, o por qué no puede tener los tipos de datos concretos (valor de tipo) en el hashtbl? Eso simplificaría las cosas. Tal como es, puede mover el cheque por bool a la Array.get y utilizar un cierre:

| 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 

Alternativamente creo que tendría más sentido para simplificar el código. Mueva los valores a Hashtbl en lugar de tener un tipo, un índice y una matriz de valores. O simplemente almacene el índice en Hashtbl y verifique el tipo en la matriz.

respuesta incorrecta ABAJO:

puede reemplazar el caso de los demás con un fósforo. O bien, puede reemplazar la let con un fósforo:

reemplazar 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 

reemplazar dejó:

| 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

El problema no es la coincidencia con el tipo de variable 'Bool | _' pero en el 'let BOOL v = var_values. (i)' ya que 'var_values' es un' value array' y forzo que el elemento i-th sea del tipo 'BOOL v' (ya que estoy seguro porque comprobé la tabla hash 'variables') .. – Jack

+0

Sí, acabo de darme cuenta y actualicé mi respuesta. –

3

En este caso particular, las variantes polimórficas, como se explica por Pascal, son una buena respuesta.

A veces, sin embargo, estás atrapado en un caso imposible. Entonces me resulta natural para escribir

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

Esto es mucho mejor que usar la bandera -w p que podría ocultar otra, el patrón no exhaustiva no deseado coincide.

Cuestiones relacionadas