Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
functor Map.make中合并的OCaml语义?_Ocaml - Fatal编程技术网

functor Map.make中合并的OCaml语义?

functor Map.make中合并的OCaml语义?,ocaml,Ocaml,我正在编写一个OCaml函数,其中需要合并两个映射。我无法理解functorMap.Make(在OCaml的3.12.0版中找到)提供的merge函数的语义。有人能给我一个比OCaml手册更详细的解释吗?一个例子可能足以让我明白这一点 此外,我需要合并的两个映射具有一些有趣的属性:键具有相同的类型(int,实际上),并且它们的域是不相交的。还有比合并例程更有效的方法吗?merge使用一个函数和两个映射。对于任一映射中存在的每个键,将调用该函数。如果键只存在于其中一个映射中,则另一个映射的值将作为

我正在编写一个OCaml函数,其中需要合并两个映射。我无法理解functor
Map.Make
(在OCaml的3.12.0版中找到)提供的
merge
函数的语义。有人能给我一个比OCaml手册更详细的解释吗?一个例子可能足以让我明白这一点


此外,我需要合并的两个映射具有一些有趣的属性:键具有相同的类型(
int
,实际上),并且它们的域是不相交的。还有比合并例程更有效的方法吗?

merge
使用一个函数和两个映射。对于任一映射中存在的每个键,将调用该函数。如果键只存在于其中一个映射中,则另一个映射的值将作为None传入(这就是为什么参数是选项)。如果函数返回
Some x
,则新映射将具有相关密钥的值
x
。否则钥匙就不存在了

例如:

let map1 = add 1 2 (add 2 3 empty);;
let map2 = add 2 5 (add 3 4 empty);;
let map3 = merge (fun k xo yo -> match xo,yo with
    | Some x, Some y -> Some (x+y)
    | _ -> None
  ) map1 map2;;
map3现在包含映射
2->8

如果将其更改为:

let map3 = merge (fun k xo yo -> match xo,yo with
    | Some x, Some y -> Some (x+y)
    | None, yo -> yo
    | xo, None -> xo
  ) map1 map2;;

它将包含基于第一个答案的映射
1->2
2->8
3->4
,,并且考虑到附加问题(在域不相交的情况下合并映射),然后我将提出以下通用合并例程:

let merge_disjoint m1 m2 = 
  IntMap.merge 
    (fun k x0 y0 -> 
       match x0, y0 with 
         None, None -> None
       | None, Some v | Some v, None -> Some v
       | _, _ -> invalid_arg "merge_disjoint: maps are not disjoint")
    m1 m2
有没有更有效的方法


--David。

由于地图是不相交的,因此您可以在较小的地图中循环并插入较大的地图:

let disjoint_merge m1 m2 =
  if (IntMap.cardinal m1) < (IntMap.cardinal m2) then
    IntMap.fold IntMap.add m1 m2
  else
    IntMap.fold IntMap.add m2 m1
它基本上遍历映射的所有元素,并调用一个函数,该函数接受键、值和其他类型的变量
'b
,并返回该类型的内容(
'b
)。在本例中,我们传递的是函数
IntMap.add
,另一个变量是我们的第二个map。因此它遍历所有元素并将它们添加到另一个映射中

编辑:您最好只做以下操作:

let disjoint_merge m1 m2 =
  IntMap.fold IntMap.add m1 m2
编辑2:更好的是:

let disjoint_merge = IntMap.fold IntMap.add;;

我刚刚查看了
cardinal
的实现,它遍历树并返回计数。因此,通过检查您正在执行的大小是O(n+m+min(n,m)log(max(n,m)),而不仅仅是O(nlog(m))。

当键的类型是
int
并且您对合并(不相交或不相交)贴图感兴趣时,值得检查表示为Patricia树的贴图是否适合您的需要。这里有一个实现:顺便说一句,如果其中一个答案解决了您的问题,您应该将其标记为已接受。这将是一个很好的
Map.union
函数。对我来说,合并贴图的想法不仅允许在相同键的情况下应用某些功能,甚至允许在一个贴图中使用键。例如,可能有人想
Map.merge(fun x y->(x,y))
我认为对merge的定义有用的一些澄清:
merge
将通过m1或m2中的所有键迭代
f
,但只保留那些返回值不是None的键。
let disjoint_merge = IntMap.fold IntMap.add;;