module Value =
struct
type t = Int of int
end
module M = Map.Make(String)
type expr =
| Num of int
| Add of expr * expr
type t = Value.t M.t (* Value.t is Int of int *)
let rec add_map (st: string list) (e: expr list) (s: t): t =
match st with
| [] -> s
| s1::st ->
match e with
| e1::e ->
M.add s1 e1 s;
add_map st e s;;
在上面的函数中,e是用户定义类型expr的列表,s是用户定义的映射“t = Int M.t”,它将int存储在字符串的键中。问题是,如果我编译这个,错误表明 e1 的类型是 t = t M.t,并且我需要 expr M.t。显然e1是expr列表的元素,为什么ocaml认为它是t?我知道 M.add 需要 (M.add string expr (map)
您没有显示确切的错误消息,但对
M.add
的调用存在问题:地图 s
的类型为 Value.t M.t
,但您为其指定了 expr
类型的值,而不是 Value.t
。
您有一个映射类型
t
将字符串映射到 Value.t
值。但在您的 add_map
函数中,您将 expr
类型的值添加到地图中。
您需要将
expr
类型的值映射到 Value.t
:
let rec expr_to_value_t = function
| Num n -> Value.Int n
| Add (e1, e2) ->
let Value.Int n1 = expr_to_value_t e1 in
let Value.Int n2 = expr_to_value_t e2 in
Value.Int (n1 + n2)
let rec add_map (st: string list) (e: expr list) (s: t): t =
match st with
| [] -> s
| s1::st ->
match e with
| e1::e ->
M.add s1 (expr_to_value_t e1) s;
add_map st e s
但是,在编译时,它确实会提示有关非详尽模式匹配的错误,更糟糕的是,在这种情况下,
M.add s1 (expr_to_value_t e1) s
不会做任何事情。 OCaml 中的映射是函数式数据结构。你不是改变它们,而是改变它们。 M.add
不会修改 s
,它只是创建一个带有附加绑定的新地图。
您可以通过对函数进行相对较少的修改来克服这个问题。
let rec add_map (st: string list) (e: expr list) (s: t): t =
match st with
| [] -> s
| s1::st ->
match e with
| e1::e ->
let s = M.add s1 (expr_to_value_t e1) s in
add_map st e s
在这里,我用新映射遮盖了原始
s
绑定,该新映射用于对 add_map
的递归调用。测试一下:
# add_map ["hello"; "world"] [Num 23; Num 42] M.empty
|> M.bindings;;
- : (string * Value.t) list =
[("hello", Value.Int 23); ("world", Value.Int 42)]
这将是使用
List.fold_left2
的好地方,假设两个列表的长度相等。否则Invalid_argument
将会被提升。
let add_map st e s =
List.fold_left2 (fun m a b -> M.add a b m) s st e