Functional programming 抑制OCaml中的穷举匹配警告

Functional programming 抑制OCaml中的穷举匹配警告,functional-programming,pattern-matching,ocaml,warnings,Functional Programming,Pattern Matching,Ocaml,Warnings,我在修复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

我在修复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
| 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
我试图定义布尔表达式中变量引用的行为,所以我要做的是

  • 检查变量是否已声明
  • 检查变量的类型是否为bool
为此,我有以下代码(
s
是变量的名称):

问题是,我的检查确保从
var\u values
中获取的元素的类型为
BOOL of BOOL
,但是编译器当然没有看到这个约束,它警告我:

警告p:此模式匹配并非详尽无遗。 以下是一个不匹配值的示例: (浮动|整数|未设置)

我该如何解决这类问题?提前感谢

查看并搜索“禁用警告”。您应该来到一个标志
-w

如果您想用“ocamlish”的方式来修复它,那么我认为您必须使模式匹配详尽无遗,即覆盖所有可能发生的情况


但是如果你不想匹配所有可能的值,你可以考虑使用通配符(见),它覆盖了所有你不想明确处理的情况。误读了你的问题。把我的答案留给后人

更新的答案:您在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:

如果出现以下情况,请更换:

| 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

这是一个您可以使用解决的问题

以下是一些可编译的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_值
仅是一个
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

在这种特殊情况下,多态性变体,如Pascal所解释的,是一个很好的答案

然而,有时候,你会遇到一个不可能的情况。然后我发现写作是很自然的

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

这比使用
-w p
标志要好得多,该标志可能会隐藏其他不需要的非穷举模式匹配。

是的,这可能会有所帮助,但有没有一种方法可以以安全的ocamlish方式修复警告而不禁用它们?@Jack真正的ocamlish方法是构建数据类型,以便不存在任何可能未使用的值。但这并不总是可行或可取的。第二种方法是添加引发异常的最终通配符模式(
\uu
)(要么是
无效的参数
,要么是模块特定的替代方案)。问题不在于变量类型
Bool |
的匹配,而是
let Bool v=var\u值的匹配。(i)
因为
var\u values
是一个
值数组
,我强制第I个元素的类型为
BOOL v
(因为我确定,因为我检查了
变量
哈希表)…作为旁白,只有当您想要对类型
var_values=value array
进行抽象,并且只让其名称在模块外部可见时,才可以声明该类型。除此之外,它是一个无用的类型别名,可能会降低错误消息的可读性。