我在修复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:此模式匹配并非详尽无遗。 以下是不匹配的值的示例: (FLOAT _ | INT _ | UNSET)
我该如何解决这类问题?提前致谢
答案 0 :(得分:8)
这是您可以使用OCaml's polymorphic variants解决的问题。
以下是我推断的一些可编辑的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
答案 1 :(得分:4)
查看this并搜索“停用警告”。你应该来一面旗帜-w
。
如果你想以“ocamlish”方式修复它,那么我认为你必须使模式匹配详尽,即涵盖可能发生的所有情况。
但是如果你不想匹配所有可能的值,你可以考虑使用通配符(参见here),它涵盖了你不想明确处理的所有情况。
答案 2 :(得分:3)
在这种特殊情况下,Pascal解释的多态变体是一个很好的答案。
然而,有时你会遇到一个不可能的案例。然后我觉得写起来很自然
(fun s -> match Array.get var_values i with
| BOOL v -> v
| _ -> assert false)
这比使用-w p
标志好得多,后者可以隐藏其他不受欢迎的非详尽模式匹配。
答案 3 :(得分:0)
糟糕!误读你的问题。留下我的答案给后人。
更新的答案:你有没有在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