[m-rev.] for review: add transform_value predicate to map.
Ian MacLarty
maclarty at cs.mu.OZ.AU
Wed Jan 12 18:37:09 AEDT 2005
For review by anyone.
Estimated hours taken: 2
Branches: main
Add transform_value predicate to map, tree234 and rbtree. This applies
a higher order argument to a value in the map. Often a value needs to be
updated using its previous value, currently requiring two lookups of the
key. With transform_value only one lookup is required.
NEWS
Mention the new predicate.
library/map.m
library/rbtree.m
library/tree234.m
Add transform_value.
library/require.m
Add a version of report_lookup_error that doesn't take a value
argument, since the value argument is not available in transform_value.
tests/hard_coded/Mmakefile
tests/hard_coded/transform_value.exp
tests/hard_coded/transform_value.m
Test transform_value.
Index: NEWS
===================================================================
RCS file: /home/mercury1/repository/mercury/NEWS,v
retrieving revision 1.360
diff -u -r1.360 NEWS
--- NEWS 11 Jan 2005 06:06:14 -0000 1.360
+++ NEWS 12 Jan 2005 07:32:41 -0000
@@ -234,7 +234,7 @@
variables. We've also added a function version.
* We've added some new predicates, map__common_subset, map__foldl3,
- and map__overlay_large_map, to map.m.
+ map__overlay_large_map and map__transform_value, to map.m.
* We've added a predicate, map_fold, to set.m.
Index: library/map.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/map.m,v
retrieving revision 1.93
diff -u -r1.93 map.m
--- library/map.m 10 Jan 2005 05:23:46 -0000 1.93
+++ library/map.m 12 Jan 2005 02:25:33 -0000
@@ -124,6 +124,20 @@
:- pred map__det_update(map(K, V)::in, K::in, V::in, map(K, V)::out) is det.
:- func map__det_update(map(K, V), K, V) = map(K, V).
+ % Update the value at the given key by applying the supplied
+ % transformation to it. Fails if the key is not found. This is faster
+ % that first searching for the value and then updating it.
+ %
+:- pred map__transform_value(pred(V, V)::in(pred(in, out) is det), K::in,
+ map(K, V)::in, map(K, V)::out) is semidet.
+
+ % Same as transform_value/4, but aborts instead of failing if the
+ % key is not found.
+ %
+:- pred map__det_transform_value(pred(V, V)::in(pred(in, out) is det), K::in,
+ map(K, V)::in, map(K, V)::out) is det.
+:- func map__det_transform_value(func(V) = V, K, map(K, V)) = map(K, V).
+
% Update value if the key is already present, otherwise
% insert new key and value.
:- pred map__set(map(K, V), K, V, map(K, V)).
@@ -563,6 +577,23 @@
;
report_lookup_error("map__det_update: key not found", K, V)
).
+
+map__transform_value(P, K, !Map) :-
+ tree234__transform_value(P, K, !Map).
+
+map__det_transform_value(P, K, !Map) :-
+ (
+ map__transform_value(P, K, !.Map, NewMap)
+ ->
+ !:Map = NewMap
+ ;
+ report_lookup_error("map__det_transform_value: key not found",
+ K)
+ ).
+
+map__det_transform_value(F, K, Map0) = Map :-
+ map__det_transform_value(pred(V0::in, V::out) is det :- V = F(V0), K,
+ Map0, Map).
map__set(Map0, K, V, Map) :-
tree234__set(Map0, K, V, Map).
Index: library/rbtree.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/rbtree.m,v
retrieving revision 1.17
diff -u -r1.17 rbtree.m
--- library/rbtree.m 11 Nov 2004 13:46:40 -0000 1.17
+++ library/rbtree.m 12 Jan 2005 02:44:45 -0000
@@ -15,6 +15,9 @@
% fails if key already in tree.
% update:
% changes value of key already in tree. fails if key doesn't exist.
+% transform_value:
+% looks up an existing value in the tree, applies a transformation to the
+% value and then updates the value. fails if the key doesn't exist.
% set:
% inserts or updates. Never fails.
%
@@ -63,6 +66,13 @@
:- pred rbtree__update(rbtree(K, V)::in, K::in, V::in, rbtree(K, V)::out)
is semidet.
+ % Update the value at the given key by applying the supplied
+ % transformation to it. Fails if the key is not found. This is faster
+ % that first searching for the value and then updating it.
+ %
+:- pred rbtree__transform_value(pred(V, V)::in(pred(in, out) is det), K::in,
+ rbtree(K, V)::in, rbtree(K, V)::out) is semidet.
+
% Sets a value regardless of whether key exists or not.
%
:- func rbtree__set(rbtree(K, V), K, V) = rbtree(K, V).
@@ -390,6 +400,43 @@
Tree = black(K0, V0, NewL, R)
;
rbtree__update(R, K, V, NewR),
+ Tree = black(K0, V0, L, NewR)
+ ).
+
+%-----------------------------------------------------------------------------%
+
+rbtree__transform_value(_P, _K, empty, _T) :-
+ fail.
+rbtree__transform_value(P, K, red(K0, V0, L, R), Tree) :-
+ compare(Result, K, K0),
+ (
+ Result = (=)
+ ->
+ P(V0, NewV),
+ Tree = red(K, NewV, L, R)
+ ;
+ Result = (<)
+ ->
+ rbtree__transform_value(P, K, L, NewL),
+ Tree = red(K0, V0, NewL, R)
+ ;
+ rbtree__transform_value(P, K, R, NewR),
+ Tree = red(K0, V0, L, NewR)
+ ).
+rbtree__transform_value(P, K, black(K0, V0, L, R), Tree) :-
+ compare(Result, K, K0),
+ (
+ Result = (=)
+ ->
+ P(V0, NewV),
+ Tree = black(K, NewV, L, R)
+ ;
+ Result = (<)
+ ->
+ rbtree__transform_value(P, K, L, NewL),
+ Tree = black(K0, V0, NewL, R)
+ ;
+ rbtree__transform_value(P, K, R, NewR),
Tree = black(K0, V0, L, NewR)
).
Index: library/require.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/require.m,v
retrieving revision 1.31
diff -u -r1.31 require.m
--- library/require.m 13 Nov 2003 17:06:11 -0000 1.31
+++ library/require.m 11 Jan 2005 08:23:22 -0000
@@ -50,6 +50,15 @@
% Key and Value. The error message will include Message
% and information about Key and Value.
+:- pred report_lookup_error(string, K).
+:- mode report_lookup_error(in, in) is erroneous.
+
+% report_lookup_error(Message, Key)
+% Call error/1 with an error message that is appropriate for
+% the failure of a lookup operation involving the specified
+% Key. The error message will include Message
+% and information about Key.
+
%-----------------------------------------------------------------------------%
:- implementation.
@@ -84,6 +93,25 @@
FunctorStr,
"\n\tValue Type: ",
ValueType
+ ],
+ ErrorString),
+ error(ErrorString).
+
+report_lookup_error(Msg, K) :-
+ KeyType = type_name(type_of(K)),
+ functor(K, Functor, Arity),
+ ( Arity = 0 ->
+ FunctorStr = Functor
+ ;
+ string__int_to_string(Arity, ArityStr),
+ string__append_list([Functor, "/", ArityStr], FunctorStr)
+ ),
+ string__append_list(
+ [Msg,
+ "\n\tKey Type: ",
+ KeyType,
+ "\n\tKey Functor: ",
+ FunctorStr
],
ErrorString),
error(ErrorString).
Index: library/tree234.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/tree234.m,v
retrieving revision 1.44
diff -u -r1.44 tree234.m
--- library/tree234.m 16 Dec 2004 03:17:28 -0000 1.44
+++ library/tree234.m 11 Jan 2005 08:08:11 -0000
@@ -115,6 +115,13 @@
% :- mode tree234__update(di_tree234, in, in, uo_tree234) is det.
% :- mode tree234__update(di, di, di, uo) is semidet.
+ % Update the value at the given key by applying the supplied
+ % transformation to it. This is faster that first searching for
+ % the value and then updating it.
+ %
+:- pred tree234__transform_value(pred(V, V)::in(pred(in, out) is det), K::in,
+ tree234(K, V)::in, tree234(K, V)::out) is semidet.
+
% count the number of elements in a tree
:- pred tree234__count(tree234(K, V), int).
:- mode tree234__count(in, out) is det.
@@ -774,6 +781,104 @@
;
Result2 = (>),
tree234__update(T3, K, V, NewT3),
+ Tout = four(K0, V0, K1, V1, K2, V2,
+ T0, T1, T2, NewT3)
+ )
+ )
+ ).
+
+%------------------------------------------------------------------------------%
+
+tree234__transform_value(P, K, Tin, Tout) :-
+ (
+ Tin = empty,
+ fail
+ ;
+ Tin = two(K0, V0, T0, T1),
+ compare(Result, K, K0),
+ (
+ Result = (<),
+ tree234__transform_value(P, K, T0, NewT0),
+ Tout = two(K0, V0, NewT0, T1)
+ ;
+ Result = (=),
+ P(V0, VNew),
+ Tout = two(K0, VNew, T0, T1)
+ ;
+ Result = (>),
+ tree234__transform_value(P, K, T1, NewT1),
+ Tout = two(K0, V0, T0, NewT1)
+ )
+ ;
+ Tin = three(K0, V0, K1, V1, T0, T1, T2),
+ compare(Result0, K, K0),
+ (
+ Result0 = (<),
+ tree234__transform_value(P, K, T0, NewT0),
+ Tout = three(K0, V0, K1, V1, NewT0, T1, T2)
+ ;
+ Result0 = (=),
+ P(V0, VNew),
+ Tout = three(K0, VNew, K1, V1, T0, T1, T2)
+ ;
+ Result0 = (>),
+ compare(Result1, K, K1),
+ (
+ Result1 = (<),
+ tree234__transform_value(P, K, T1, NewT1),
+ Tout = three(K0, V0, K1, V1, T0, NewT1, T2)
+ ;
+ Result1 = (=),
+ P(V1, VNew),
+ Tout = three(K0, V0, K1, VNew, T0, T1, T2)
+ ;
+ Result1 = (>),
+ tree234__transform_value(P, K, T2, NewT2),
+ Tout = three(K0, V0, K1, V1, T0, T1, NewT2)
+ )
+ )
+ ;
+ Tin = four(K0, V0, K1, V1, K2, V2, T0, T1, T2, T3),
+ compare(Result1, K, K1),
+ (
+ Result1 = (<),
+ compare(Result0, K, K0),
+ (
+ Result0 = (<),
+ tree234__transform_value(P, K, T0, NewT0),
+ Tout = four(K0, V0, K1, V1, K2, V2,
+ NewT0, T1, T2, T3)
+ ;
+ Result0 = (=),
+ P(V0, VNew),
+ Tout = four(K0, VNew, K1, V1, K2, V2,
+ T0, T1, T2, T3)
+ ;
+ Result0 = (>),
+ tree234__transform_value(P, K, T1, NewT1),
+ Tout = four(K0, V0, K1, V1, K2, V2,
+ T0, NewT1, T2, T3)
+ )
+ ;
+ Result1 = (=),
+ P(V1, VNew),
+ Tout = four(K0, V0, K1, VNew, K2, V2, T0, T1, T2, T3)
+ ;
+ Result1 = (>),
+ compare(Result2, K, K2),
+ (
+ Result2 = (<),
+ tree234__transform_value(P, K, T2, NewT2),
+ Tout = four(K0, V0, K1, V1, K2, V2,
+ T0, T1, NewT2, T3)
+ ;
+ Result2 = (=),
+ P(V2, VNew),
+ Tout = four(K0, V0, K1, V1, K2, VNew,
+ T0, T1, T2, T3)
+ ;
+ Result2 = (>),
+ tree234__transform_value(P, K, T3, NewT3),
Tout = four(K0, V0, K1, V1, K2, V2,
T0, T1, T2, NewT3)
)
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.246
diff -u -r1.246 Mmakefile
--- tests/hard_coded/Mmakefile 10 Jan 2005 01:47:30 -0000 1.246
+++ tests/hard_coded/Mmakefile 12 Jan 2005 02:33:26 -0000
@@ -170,6 +170,7 @@
time_test \
tim_qual1 \
trans_intermod_user_equality \
+ transform_value \
transitive_inst_type \
tuple_test \
tuple_test \
Index: tests/hard_coded/transform_value.exp
===================================================================
RCS file: tests/hard_coded/transform_value.exp
diff -N tests/hard_coded/transform_value.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/transform_value.exp 12 Jan 2005 02:55:00 -0000
@@ -0,0 +1,6 @@
+2
+key not found
+2
+2
+[1 - 2, 2 - 2, 3 - 2, 4 - 2, 5 - 2, 6 - 2, 7 - 2, 8 - 2]
+[1 - 2, 2 - 2]
Index: tests/hard_coded/transform_value.m
===================================================================
RCS file: tests/hard_coded/transform_value.m
diff -N tests/hard_coded/transform_value.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/transform_value.m 12 Jan 2005 02:54:48 -0000
@@ -0,0 +1,73 @@
+% Test the map.transform_value predicate.
+%
+
+:- module transform_value.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module map, int, svmap, list, assoc_list, rbtree.
+
+main(!IO) :-
+ some [!M] (
+ !:M = map.init,
+ svmap.set(1, 1, !M),
+ svmap.set(2, 1, !M),
+ svmap.set(3, 1, !M),
+ svmap.set(4, 1, !M),
+ svmap.set(5, 1, !M),
+ svmap.set(6, 1, !M),
+ svmap.set(7, 1, !M),
+ svmap.set(8, 1, !M),
+ M0 = !.M,
+ ( map.transform_value(add1, 2, !.M, M1) ->
+ io.write_int(M1 ^ det_elem(2), !IO)
+ ;
+ io.write_string("key not found", !IO)
+ ),
+ io.nl(!IO),
+ ( map.transform_value(add1, 9, !.M, M2) ->
+ io.write_int(M2 ^ det_elem(9), !IO)
+ ;
+ io.write_string("key not found", !IO)
+ ),
+ io.nl(!IO),
+ map.det_transform_value(add1, 3, !M),
+ io.write_int(!.M ^ det_elem(3), !IO),
+ io.nl(!IO),
+ M3 = map.det_transform_value(f, 7, !.M),
+ io.write_int(M3 ^ det_elem(7), !IO),
+ io.nl(!IO),
+ list.foldl(map.det_transform_value(add1),
+ [1, 2, 3, 4, 5, 6, 7, 8], M0, M4),
+ A`with_type`assoc_list(int, int) = map.to_assoc_list(M4),
+ io.write(A, !IO),
+ io.nl(!IO),
+ RB0 = rbtree.init,
+ rbtree.set(RB0, 1, 1, RB1),
+ rbtree.set(RB1, 2, 1, RB2),
+ (
+ rbtree.transform_value(add1, 1, RB2, RB3),
+ rbtree.transform_value(add1, 2, RB3, RB4)
+ ->
+ A2`with_type`assoc_list(int, int) =
+ rbtree.rbtree_to_assoc_list(RB4),
+ io.write(A2, !IO)
+ ;
+ io.write_string("key not found", !IO)
+ ),
+ io.nl(!IO)
+ ).
+
+:- pred add1(int::in, int::out) is det.
+
+add1(X, X+1).
+
+:- func f(int) = int.
+
+f(X) = X+1.
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list