[m-rev.] for review: Add map.merge/4
Paul Bone
paul at bone.id.au
Tue Dec 10 12:55:21 AEDT 2013
Branches: master
Add map.merge/4
This version of map.merge takes an additional parameter allowing the callee
to specify how conflicting key-value pairs should be handled. This is
useful when the values for a given key need to be merged in some way.
merge's parameter order looks like: merge(ResulveFunc, MapA, MapB, Map).
The current implementation runs in linear time with respect to its first
argument, this is different from the existing merge/3 predicate. Before
committing this I'd like to determine which argument order is preferred and
if it is worthwhile changing the argument order of merge/4 (this
contribution) to conform with the established order or somehow transitioning
to a new argument order. Another option is using a different name for this
slightly different predicate (this may be good regardless of the argument
order discussion).
Thanks.
library/map.m:
As above.
NEWS:
List the new predicate and function.
---
NEWS | 4 ++--
library/map.m | 34 ++++++++++++++++++++++++++++++++--
2 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/NEWS b/NEWS
index 496c14e..22e90ff 100644
--- a/NEWS
+++ b/NEWS
@@ -15,8 +15,8 @@ Changes to the Mercury standard library:
* We have added the following predicates to the array and version_array
modules: is_empty/1, all_true/2 and all_false/2.
-* We have added the following functions to the map module: det_min_key/1
- and det_max_key/1.
+* We have added the following functions to the map module: det_min_key/1,
+ det_max_key/1 and merge/3. We have also added the predicate merge/4.
* We have added the following predicates to the list module: foldr2/6 and
foldr3/8.
diff --git a/library/map.m b/library/map.m
index ebeecf5..3a52617 100644
--- a/library/map.m
+++ b/library/map.m
@@ -299,8 +299,19 @@
% in the second map, so for efficiency, you want to put the bigger map
% first and the smaller map second.
%
-:- func map.merge(map(K, V), map(K, V)) = map(K, V).
-:- pred map.merge(map(K, V)::in, map(K, V)::in, map(K, V)::out) is det.
+:- func merge(map(K, V), map(K, V)) = map(K, V).
+:- pred merge(map(K, V)::in, map(K, V)::in, map(K, V)::out) is det.
+
+ % Merge two maps resolving disjoint keys.
+ %
+ % If a value is present in both maps then the higher
+ % order value is used to resolve the conflict. The implementation takes
+ % time proportional to the size of MapA. So for efficiency you want to
+ % put the smaller map first and the larger one second.
+ %
+:- func merge(func(K, V, V) = V, map(K, V), map(K, V)) = map(K, V).
+:- pred merge((func(K, V, V) = V)::in, map(K, V)::in,
+ map(K, V)::in, map(K, V)::out) is det.
% For map.overlay(MapA, MapB, Map), if MapA and MapB both contain the
% same key, then Map will map that key to the value from MapB.
@@ -1142,6 +1153,25 @@ map.merge(MA, MB, M) :-
%-----------------------------------------------------------------------------%
+merge(Resolve, MA, MB) = Map :-
+ merge(Resolve, MA, MB, Map).
+
+merge(Resolve, MA, MB, Map) :-
+ map.foldl(merge_item(Resolve), MA, MB, Map).
+
+:- pred merge_item((func(K, V, V) = V)::in, K::in, V::in,
+ map(K, V)::in, map(K, V)::out) is det.
+
+merge_item(Resolve, KA, VA, !Map) :-
+ ( map.search(!.Map, KA, VB) ->
+ V = Resolve(KA, VA, VB),
+ map.det_update(KA, V, !Map)
+ ;
+ map.det_insert(KA, VA, !Map)
+ ).
+
+%-----------------------------------------------------------------------------%
+
map.old_merge(M1, M2) = M3 :-
map.old_merge(M1, M2, M3).
--
1.8.5.1
More information about the reviews
mailing list