[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