[m-rev.] for review: fix behaviour of bimap.from_assoc_list

Julien Fischer juliensf at cs.mu.OZ.AU
Tue Mar 15 13:52:26 AEDT 2005


Is anybody going to review this?

On Thu, 10 Mar 2005, Julien Fischer wrote:

> In view of that and the other review comments here is modified diff.  I've
> also improved the documentation in the bimap module and added some new
> higher-order predicates as well.
>
> Estimated hours taken: 3
> Branches: main, release
>
> library/bimap.m:
> 	Document the procedures in this module much more then
> 	we currently do.  In particular, note conditions for
> 	which procedure fail or throw exceptions more carefully
> 	than we previously did.
>
> 	Change bimap.from_assoc_list so that it fails if the
> 	association list does not implicitly define a bijection.
> 	Previously, it has been possible to use this to create
> 	bimaps that were not bijective.  Add a det version
> 	called bimap.det_from_assoc_list.
>
> 	Add bimap.foldl2 and bimap.foldl3.
>
> 	Alter the ordering of predicate and function versions
> 	of the same procedure where they don't conform to
> 	our coding standard.
>
> 	Remove the comment at the head of the file that says
> 	that the implementation is a pair of maps.  Since the
> 	type has been abstract for a while now, the details
> 	of it's implementation are not useful.
>
> 	Add an end_module declaration to this module.
>
> Julien.
>
> Index: library/bimap.m
> ===================================================================
> RCS file: /home/mercury1/repository/mercury/library/bimap.m,v
> retrieving revision 1.16.2.2
> diff -u -r1.16.2.2 bimap.m
> --- library/bimap.m	7 Mar 2005 03:02:25 -0000	1.16.2.2
> +++ library/bimap.m	10 Mar 2005 04:20:41 -0000
> @@ -13,8 +13,6 @@
>  % of (Key, Data) pairs which allows you to look up any Data item given the
>  % Key.  A bimap also allows you to look up the Key given the Data.
>  %
> -% The implementation is a pair of maps.
> -%
>  %-----------------------------------------------------------------------------%
>  %-----------------------------------------------------------------------------%
>
> @@ -30,150 +28,269 @@
>
>  	% Initialize an empty bimap.
>  	%
> -:- pred bimap__init(bimap(K, V)::out) is det.
>  :- func bimap__init = bimap(K, V).
> +:- pred bimap__init(bimap(K, V)::out) is det.
>
>  	% Check whether a bimap is empty.
>  	%
>  :- pred bimap__is_empty(bimap(K, V)::in) is semidet.
>
> +	% Search the bimap.
> +	% The first mode searches for a value given a key and the second
> +	% mode searches for a key given a value.
> +	%
>  :- pred bimap__search(bimap(K, V), K, V).
>  :- mode bimap__search(in, in, out) is semidet.
>  :- mode bimap__search(in, out, in) is semidet.
>
> -:- pred bimap__forward_search(bimap(K, V)::in, K::in, V::out) is semidet.
> +	% Search the bimap for the value corresponding to a given key.
> +	%
>  :- func bimap__forward_search(bimap(K, V), K) = V is semidet.
> +:- pred bimap__forward_search(bimap(K, V)::in, K::in, V::out) is semidet.
>
> -:- pred bimap__reverse_search(bimap(K, V)::in, K::out, V::in) is semidet.
> +	% Search the bimap for the key corresponding to the given value.
> +	%
>  :- func bimap__reverse_search(bimap(K, V), V) = K is semidet.
> +:- pred bimap__reverse_search(bimap(K, V)::in, K::out, V::in) is semidet.
>
> -:- pred bimap__lookup(bimap(K, V)::in, K::in, V::out) is det.
> +	% Look up the value in the bimap corresponding to the given key.
> +	% Throws an exception if the key is not present in the bimap.
> +	%
>  :- func bimap__lookup(bimap(K, V), K) = V.
> +:- pred bimap__lookup(bimap(K, V)::in, K::in, V::out) is det.
>
> -:- pred bimap__reverse_lookup(bimap(K, V)::in, K::out, V::in) is det.
> +	% Look up the key in the bimap corresponding to the given value.
> +	% Throws an exception if the value is not present in the bimap.
> +	%
>  :- func bimap__reverse_lookup(bimap(K, V), V) = K.
> +:- pred bimap__reverse_lookup(bimap(K, V)::in, K::out, V::in) is det.
>
>  	% Given a bimap, return a list of all the keys in the bimap.
>  	%
> -:- pred bimap__ordinates(bimap(K, V)::in, list(K)::out) is det.
>  :- func bimap__ordinates(bimap(K, V)) = list(K).
> +:- pred bimap__ordinates(bimap(K, V)::in, list(K)::out) is det.
>
>  	% Given a bimap, return a list of all the data values in the bimap.
>  	%
> -:- pred bimap__coordinates(bimap(K, V)::in, list(V)::out) is det.
>  :- func bimap__coordinates(bimap(K, V)) = list(V).
> +:- pred bimap__coordinates(bimap(K, V)::in, list(V)::out) is det.
>
> +	% Succeeds iff the bimap contains the given key.
> +	%
>  :- pred bimap__contains_key(bimap(K, V)::in, K::in) is semidet.
>
> +	% Succeeds iff the bimap contains the given value.
> +	%
>  :- pred bimap__contains_value(bimap(K, V)::in, V::in) is semidet.
>
> +	% Insert a new key-value pair into the bimap.
> +	% Fails if either the key or value already exists.
> +	%
> +:- func bimap__insert(bimap(K, V), K, V) = bimap(K, V) is semidet.
>  :- pred bimap__insert(bimap(K, V)::in, K::in, V::in, bimap(K, V)::out)
>  	is semidet.
> -:- func bimap__insert(bimap(K, V), K, V) = bimap(K, V) is semidet.
>
> +	% As above but throws an exception if the key or value already
> +	% exists.
> +	%
> +:- func bimap__det_insert(bimap(K, V), K, V) = bimap(K, V).
>  :- pred bimap__det_insert(bimap(K, V)::in, K::in, V::in, bimap(K, V)::out)
>  	is det.
> -:- func bimap__det_insert(bimap(K, V), K, V) = bimap(K, V).
>
> -:- pred bimap__set(bimap(K, V)::in, K::in, V::in, bimap(K, V)::out) is det.
> +	% Update the key and value if already present, otherwise insert the
> +	% new key and value.
> +	%
> +	% NOTE: setting the key-value pair (K, V) will remove the
> +	%       key-value pairs (K, V1) and (K1, V) if they exist.
> +	%
>  :- func bimap__set(bimap(K, V), K, V) = bimap(K, V).
> +:- pred bimap__set(bimap(K, V)::in, K::in, V::in, bimap(K, V)::out) is det.
>
> -:- pred bimap__det_insert_from_assoc_list(assoc_list(K, V)::in,
> -	bimap(K, V)::in, bimap(K, V)::out) is det.
> +	% Insert key-value pairs from an association list into the given
> +	% bimap.  Fails if the contents of the association list and the
> +	% initial bimap do not implicitly form a bijection.
> +	%
> +:- func bimap__insert_from_assoc_list(assoc_list(K, V), bimap(K, V)) =
> +	bimap(K, V) is semidet.
> +:- pred bimap__insert_from_assoc_list(assoc_list(K, V)::in,
> +	bimap(K, V)::in, bimap(K, V)::out) is semidet.
> +
> +	% As above but throws an exception if the association list and
> +	% initial bimap are not implicitly bijective.
> +	%
>  :- func bimap__det_insert_from_assoc_list(assoc_list(K, V), bimap(K, V))
>  	= bimap(K, V).
> -
> -:- pred bimap__det_insert_from_corresponding_lists(list(K)::in, list(V)::in,
> +:- pred bimap__det_insert_from_assoc_list(assoc_list(K, V)::in,
>  	bimap(K, V)::in, bimap(K, V)::out) is det.
> +
> +	% Insert key-value pairs from a pair of corresponding lists.
> +	% Throws an exception if the lists are not of equal lengths
> +	% or if they do not implicitly define a bijection.
> +	%
>  :- func bimap__det_insert_from_corresponding_lists(list(K), list(V),
>  	bimap(K, V)) = bimap(K, V).
> -
> -:- pred bimap__set_from_assoc_list(assoc_list(K, V)::in,
> +:- pred bimap__det_insert_from_corresponding_lists(list(K)::in, list(V)::in,
>  	bimap(K, V)::in, bimap(K, V)::out) is det.
> +
> +	% Apply bimap.set to each key-value pair in the association
> +	% list.  The key-value pairs from the association list may
> +	% update existing keys and values in the bimap.
> +	%
>  :- func bimap__set_from_assoc_list(assoc_list(K, V), bimap(K, V))
>  	= bimap(K, V).
> -
> -:- pred bimap__set_from_corresponding_lists(list(K)::in, list(V)::in,
> +:- pred bimap__set_from_assoc_list(assoc_list(K, V)::in,
>  	bimap(K, V)::in, bimap(K, V)::out) is det.
> +
> +	% As above but with a pair of corresponding lists in place
> +	% of an association list.  Throws an exception if the lists
> +	% are not of equal length.
> +	%
>  :- func bimap__set_from_corresponding_lists(list(K), list(V),
>  	bimap(K, V)) = bimap(K, V).
> +:- pred bimap__set_from_corresponding_lists(list(K)::in, list(V)::in,
> +	bimap(K, V)::in, bimap(K, V)::out) is det.
>
>  	% Delete a key-value pair from a bimap. If the key is not present,
>  	% leave the bimap unchanged.
>  	%
> -:- pred bimap__delete_key(K::in, bimap(K, V)::in, bimap(K, V)::out) is det.
>  :- func bimap__delete_key(bimap(K, V), K) = bimap(K, V).
> +:- pred bimap__delete_key(K::in, bimap(K, V)::in, bimap(K, V)::out) is det.
>
>  	% Delete a key-value pair from a bimap. If the value is not present,
>  	% leave the bimap unchanged.
>  	%
> -:- pred bimap__delete_value(V::in, bimap(K, V)::in, bimap(K, V)::out) is det.
>  :- func bimap__delete_value(bimap(K, V), V) = bimap(K, V).
> +:- pred bimap__delete_value(V::in, bimap(K, V)::in, bimap(K, V)::out) is det.
>
> -	% Apply bimap__delete_key to a list of keys.
> +	% Apply bimap.delete_key to a list of keys.
>  	%
> +:- func bimap__delete_keys(bimap(K, V), list(K)) = bimap(K, V).
>  :- pred bimap__delete_keys(list(K)::in, bimap(K, V)::in, bimap(K, V)::out)
>  	is det.
> -:- func bimap__delete_keys(bimap(K, V), list(K)) = bimap(K, V).
>
> -	% Apply bimap__delete_value to a list of values.
> +	% Apply bimap.delete_value to a list of values.
>  	%
> +:- func bimap__delete_values(bimap(K, V), list(V)) = bimap(K, V).
>  :- pred bimap__delete_values(list(V)::in, bimap(K, V)::in, bimap(K, V)::out)
>  	is det.
> -:- func bimap__delete_values(bimap(K, V), list(V)) = bimap(K, V).
>
> -	% bimap__overlay(BIMapA, BIMapB, BIMap):
> +	% bimap.overlay(BIMapA, BIMapB, BIMap):
>  	% Apply map__overlay to the forward maps of BIMapA and BIMapB,
>  	% and compute the reverse map from the resulting map.
>  	%
> +:- func bimap__overlay(bimap(K, V), bimap(K, V)) = bimap(K, V).
>  :- pred bimap__overlay(bimap(K, V)::in, bimap(K, V)::in, bimap(K, V)::out)
>  	is det.
> -:- func bimap__overlay(bimap(K, V), bimap(K, V)) = bimap(K, V).
>
>  	% Convert a bimap to an association list.
>  	%
> -:- pred bimap__to_assoc_list(bimap(K, V)::in, assoc_list(K, V)::out) is det.
>  :- func bimap__to_assoc_list(bimap(K, V)) = assoc_list(K, V).
> +:- pred bimap__to_assoc_list(bimap(K, V)::in, assoc_list(K, V)::out) is det.
>
>  	% Convert an association list to a bimap.
> -	%
> -:- pred bimap__from_assoc_list(assoc_list(K, V)::in, bimap(K, V)::out) is det.
> -:- func bimap__from_assoc_list(assoc_list(K, V)) = bimap(K, V).
> +	% Fails if the association list does not implicitly define
> +	% a bijection, i.e. a key or value occurs multiple times in the
> +	% association list.
> +	%
> +:- func bimap__from_assoc_list(assoc_list(K, V)) = bimap(K, V) is semidet.
> +:- pred bimap__from_assoc_list(assoc_list(K, V)::in, bimap(K, V)::out)
> +	is semidet.
> +
> +	% As above but throws an exception instead of failing if the
> +	% association list does not implicitly defined a bijection.
> +	%
> +:- func bimap__det_from_assoc_list(assoc_list(K, V)) = bimap(K, V).
> +:- pred bimap__det_from_assoc_list(assoc_list(K, V)::in, bimap(K, V)::out) is det.
>
> +	% Convert a pair of lists into a bimap.
> +	% Fails if the lists do not implicitly define a bijection or
> +	% if the lists are of unequal length.
> +	%
> +:- func bimap__from_corresponding_lists(list(K), list(V)) = bimap(K, V)
> +	is semidet.
>  :- pred bimap__from_corresponding_lists(list(K)::in, list(V)::in,
> +	bimap(K, V)::out) is semidet.
> +
> +	% As above but throws an exception instead of failing if the
> +	% lists do not implicitly define a bijection or are of unequal
> +	% length.
> +	%
> +:- func bimap__det_from_corresponding_lists(list(K), list(V)) = bimap(K, V).
> +:- pred bimap__det_from_corresponding_lists(list(K)::in, list(V)::in,
>  	bimap(K, V)::out) is det.
> -:- func bimap__from_corresponding_lists(list(K), list(V)) = bimap(K, V).
>
> +:- func bimap__apply_forward_map_to_list(bimap(K, V), list(K)) = list(V).
>  :- pred bimap__apply_forward_map_to_list(bimap(K, V)::in, list(K)::in,
>  	list(V)::out) is det.
> -:- func bimap__apply_forward_map_to_list(bimap(K, V), list(K)) = list(V).
>
> +:- func bimap__apply_reverse_map_to_list(bimap(K, V), list(V)) = list(K).
>  :- pred bimap__apply_reverse_map_to_list(bimap(K, V)::in, list(V)::in,
>  	list(K)::out) is det.
> -:- func bimap__apply_reverse_map_to_list(bimap(K, V), list(V)) = list(K).
>
>  	% Apply a transformation predicate to all the keys.
> +	% Throws an exception if the resulting bimap is not bijective.
>  	%
> +:- func bimap__map_keys(func(V, K) = L, bimap(K, V)) = bimap(L, V).
>  :- pred bimap__map_keys(pred(V, K, L)::in(pred(in, in, out) is det),
>  	bimap(K, V)::in, bimap(L, V)::out) is det.
> -:- func bimap__map_keys(func(V, K) = L, bimap(K, V)) = bimap(L, V).
>
>  	% Apply a transformation predicate to all the values.
> +	% Throws an exception if the resulting bimap is not bijective.
>  	%
> +:- func bimap__map_values(func(K, V) = W, bimap(K, V)) = bimap(K, W).
>  :- pred bimap__map_values(pred(K, V, W)::in(pred(in, in, out) is det),
>  	bimap(K, V)::in, bimap(K, W)::out) is det.
> -:- func bimap__map_values(func(K, V) = W, bimap(K, V)) = bimap(K, W).
>
> -	% Apply a transformation predicate to all the values.
> +	% Perform a traversal of the bimap, applying an accumulator
> +	% predicate for each key-value pair.
>  	%
> +:- func bimap__foldl(func(K, V, T) = T, bimap(K, V), T) = T.
>  :- pred bimap__foldl(pred(K, V, T, T), bimap(K, V), T, T).
> -:- mode bimap__foldl(pred(in, in, di, uo) is det, in, di, uo) is det.
>  :- mode bimap__foldl(pred(in, in, in, out) is det, in, in, out) is det.
>  :- mode bimap__foldl(pred(in, in, in, out) is semidet, in, in, out) is semidet.
> -:- func bimap__foldl(func(K, V, T) = T, bimap(K, V), T) = T.
> +:- mode bimap__foldl(pred(in, in, di, uo) is det, in, di, uo) is det.
>
> +	% Perform a traversal of the bimap, applying an accumulator
> +	% predicate with two accumulators for each key-value pair.
> +	% (Although no more expressive than bimap.foldl, this is often
> +	% a more convenient format, and a little more efficient).
> +	%
> +:- pred bimap__foldl2(pred(K, V, T, T, U, U), bimap(K, V), T, T, U, U).
> +:- mode bimap__foldl2(pred(in, in, in, out, in, out) is det,
> +	in, in, out, in, out) is det.
> +:- mode bimap__foldl2(pred(in, in, in, out, in, out) is semidet,
> +	in, in, out, in, out) is semidet.
> +:- mode bimap__foldl2(pred(in, in, in, out, di, uo) is det,
> +	in, in, out, di, uo) is det.
> +:- mode bimap__foldl2(pred(in, in, di, uo, di, uo) is det,
> +	in, di, uo, di, uo) is det.
> +
> +	% Perform a traversal of the bimap, applying an accumulator
> +	% predicate with three accumulators for each key-value pair.
> +	% (Although no more expressive than bimap.foldl, this is often
> +	% a more convenient format, and a little more efficient).
> +	%
> +:- pred bimap__foldl3(pred(K, V, T, T, U, U, W, W), bimap(K, V),
> +	T, T, U, U, W, W).
> +:- mode bimap__foldl3(pred(in, in, in, out, in, out, in, out) is det,
> +	in, in, out, in, out, in, out) is det.
> +:- mode bimap__foldl3(pred(in, in, in, out, in, out, in, out) is semidet,
> +	in, in, out, in, out, in, out) is semidet.
> +:- mode bimap__foldl3(pred(in, in, in, out, in, out, di, uo) is det,
> +	in, in, out, in, out, di, uo) is det.
> +:- mode bimap__foldl3(pred(in, in, in, out, di, uo, di, uo) is det,
> +	in, in, out, di, uo, di, uo) is det.
> +:- mode bimap__foldl3(pred(in, in, di, uo, di, uo, di, uo) is det,
> +	in, di, uo, di, uo, di, uo) is det.
> +
> +	% Extract a the forward map from the bimap, the map
> +	% from key to value.
> +	%
>  :- func bimap__forward_map(bimap(K, V)) = map(K, V).
>
> +	% Extract the reverse map from the bimap, the map
> +	% from value to key.
> +	%
>  :- func bimap__reverse_map(bimap(K, V)) = map(V, K).
>
>  %-----------------------------------------------------------------------------%
> @@ -256,7 +373,15 @@
>  		map__det_insert(Reverse1, V, K, Reverse),
>  		Forward = Forward1
>  	).
> -
> +
> +bimap__insert_from_assoc_list(List, BM0) = BM :-
> +	bimap__insert_from_assoc_list(List, BM0, BM).
> +
> +bimap__insert_from_assoc_list([], !BM).
> +bimap__insert_from_assoc_list([ Key - Value | KeyValues], !BM) :-
> +	bimap__insert(!.BM, Key, Value, !:BM),
> +	bimap__insert_from_assoc_list(KeyValues, !BM).
> +
>  bimap__det_insert_from_assoc_list([], !BM).
>  bimap__det_insert_from_assoc_list([Key - Value | KeysValues], !BM) :-
>  	bimap__det_insert(!.BM, Key, Value, !:BM),
> @@ -332,15 +457,26 @@
>  bimap__to_assoc_list(bimap(Forward, _), L) :-
>  	map__to_assoc_list(Forward, L).
>
> -bimap__from_assoc_list(L, bimap(Forward, Reverse)) :-
> -	map__from_assoc_list(L, Forward),
> -	assoc_list__reverse_members(L, L1),
> -	map__from_assoc_list(L1, Reverse).
> +bimap__from_assoc_list(L, Bimap) :-
> +	bimap__insert_from_assoc_list(L, bimap.init, Bimap).
> +
> +bimap__det_from_assoc_list(L) = Bimap :-
> +	bimap__det_from_assoc_list(L, Bimap).
> +
> +bimap__det_from_assoc_list(L, Bimap) :-
> +	bimap__det_insert_from_assoc_list(L, bimap.init, Bimap).
>
>  bimap__from_corresponding_lists(Ks, Vs, BM) :-
>  	assoc_list__from_corresponding_lists(Ks, Vs, L),
>  	bimap__from_assoc_list(L, BM).
>
> +bimap__det_from_corresponding_lists(Ks, Vs) = BM :-
> +	bimap__det_from_corresponding_lists(Ks, Vs, BM).
> +
> +bimap__det_from_corresponding_lists(Ks, Vs, BM) :-
> +	assoc_list__from_corresponding_lists(Ks, Vs, L),
> +	bimap__det_from_assoc_list(L, BM).
> +
>  bimap__apply_forward_map_to_list(bimap(Forward, _), Ks, Vs) :-
>  	map__apply_to_list(Ks, Forward, Vs).
>
> @@ -350,22 +486,22 @@
>  bimap__map_keys(KeyMap, BM0, BM) :-
>  	bimap__to_assoc_list(BM0, L0),
>  	bimap__map_keys_2(KeyMap, L0, [], L),
> -	bimap__from_assoc_list(L, BM).
> +	bimap__det_from_assoc_list(L, BM).
>
>  bimap__map_keys(KeyMap, BM0) = BM :-
>  	bimap__to_assoc_list(BM0, L0),
>  	bimap__map_keys_func_2(KeyMap, L0, [], L),
> -	bimap__from_assoc_list(L, BM).
> +	bimap__det_from_assoc_list(L, BM).
>
>  bimap__map_values(ValueMap, BM0, BM) :-
>  	bimap__to_assoc_list(BM0, L0),
>  	bimap__map_values_2(ValueMap, L0, [], L),
> -	bimap__from_assoc_list(L, BM).
> +	bimap__det_from_assoc_list(L, BM).
>
>  bimap__map_values(ValueMap, BM0) = BM :-
>  	bimap__to_assoc_list(BM0, L0),
>  	bimap__map_values_func_2(ValueMap, L0, [], L),
> -	bimap__from_assoc_list(L, BM).
> +	bimap__det_from_assoc_list(L, BM).
>
>  :- pred bimap__map_keys_2(pred(V, K, L)::in(pred(in, in, out) is det),
>  	assoc_list(K, V)::in, assoc_list(L, V)::in, assoc_list(L, V)::out)
> @@ -410,6 +546,12 @@
>  bimap__foldl(Pred, bimap(Forward, _), List0, List) :-
>  	map__foldl(Pred, Forward, List0, List).
>
> +bimap__foldl2(Pred, bimap(Forward, _), !A, !B) :-
> +	map__foldl2(Pred, Forward, !A, !B).
> +
> +bimap__foldl3(Pred, bimap(Forward, _), !A, !B, !C) :-
> +	map__foldl3(Pred, Forward, !A, !B, !C).
> +
>  %-----------------------------------------------------------------------------%
>  %-----------------------------------------------------------------------------%
>  % Ralph Becket <rwab1 at cl.cam.ac.uk> 29/04/99
> @@ -493,3 +635,7 @@
>  bimap__forward_map(bimap(Forward, _)) = Forward.
>
>  bimap__reverse_map(bimap(_, Reverse)) = Reverse.
> +
> +%----------------------------------------------------------------------------%
> +:- end_module bimap.
> +%----------------------------------------------------------------------------%
> --------------------------------------------------------------------------
> 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
> --------------------------------------------------------------------------
>
--------------------------------------------------------------------------
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