为什么ocaml总是出现miss理解类型?

问题描述 投票:0回答:2
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)

ocaml
2个回答
3
投票

您没有显示确切的错误消息,但对

M.add
的调用存在问题:地图
s
的类型为
Value.t M.t
,但您为其指定了
expr
类型的值,而不是
 Value.t


1
投票

您有一个映射类型

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
© www.soinside.com 2019 - 2024. All rights reserved.