我正在尝试在OCaml中编写一个解决逻辑运算的函数。这次尝试很成功:
let rec tf =function
|B b->b
|V s->failwith "not good"
|And(e1,e2)->tf e1&&tf e2
|Or(e1,e2)->tf e1||tf e2
|Neg b-> not (tf b);;
但是当我编写以下函数时,程序会警告我一些错误:
type bv = B of bool | V of string | Neg of bv
| And of bv * bv | Or of bv * bv;;
module MS=Map.Make(String);;
let prop x map=
let rec aux=function
|B b->b
|Neg b-> not (aux b)
|V s->try aux(B (MS.find s map)) with Not_found->failwith ""
|And(e1,e2)->aux e1&&aux e2
|Or(e1,e2)->aux e1||aux e2
in aux x;;
Characters 145-148:
|And(e1,e2)->aux e1&&aux e2
^^^
Error: This variant pattern is expected to have type exn
The constructor And does not belong to type exn
其中map是(string * bool)地图。如果函数的参数“x”是一个字符串,那么它将在map中查找并获取布尔值,然后在进一步的微积分中使用它。如果找不到x,它会抛出异常并结束该函数。 我知道它与V s匹配有关但我不知道这里有什么问题
答案 0 :(得分:4)
让我说明一下,知道OCaml语法的压头会如何缩进代码:
let prop x map=
let rec aux=function
|B b->b
|Neg b-> not (aux b)
|V s->try aux(B (MS.find s map)) with Not_found->failwith ""
| And(e1,e2)->aux e1&&aux e2
| Or(e1,e2)->aux e1||aux e2
in aux x;;
现在,很明显,为什么And
和Or
应该是例外。
您可以将您的呼叫括号括起来,例如,
let prop x map =
let rec aux=function
|B b->b
|Neg b-> not (aux b)
|V s-> (try aux(B (MS.find s map)) with Not_found->failwith "")
|And(e1,e2)->aux e1&&aux e2
|Or(e1,e2)->aux e1||aux e2
in aux x;;
但是,在每个递归调用周围安装异常处理程序并不是一个好主意,因为这会导致在堆栈上安装N
异常记录,从而破坏了尾递归的概念。最好按如下方式重写算法:
let prop x map=
let rec aux=function
|B b->b
|Neg b-> not (aux b)
|V s when MS.mem s map -> aux (B (MS.find s map))
|V s -> invalid_arg ("Unbound variable: " ^ s)
|And(e1,e2) -> aux e1&&aux e2
|Or(e1,e2) -> aux e1||aux e2 in
aux x