[m-rev.] for post-commit review: improve bag.m

Julien Fischer jfischer at opturion.com
Thu Sep 17 13:35:43 AEST 2015


Hi Zoltan,

> Improve bag.m.
> 
> library/bag.m:
>     The old implementations of bag.subtract, bag.least_upper_bound,
>     bag.union, bag.intersect iterated over their second bag arguments,
>     and did a logarithmic amount of work in each iteration. This is good
>     if the second bag is small, but not if it is big. Keep those
>     implementations as the implementation of bag.subtract_small,
>     bag.least_upper_bound_small etc, and replace the implementation
>     of bag.subtract etc with code that iterates over the assoc_list version
>     of both bags. This does work that linear in total size of the two sets.

This aspect of the change needs to be mentioned in the NEWS file.

>     Replace the implementation of bag.subset_compare with one
>     that actually works.
>
>     Replace the implementation of bag.is_subbag with one that
>     does significantly less work.
>
>     Group related predicates together.
>
>     Improve the documentation of the exported predicates.
>
>     Use a more descriptive and more consistent set of variable names.

...

> diff --git a/library/bag.m b/library/bag.m
> index f309954..327ff35 100644
> --- a/library/bag.m
> +++ b/library/bag.m
> @@ -26,88 +26,74 @@

...

> +    % Given a bag, produce a set containing all the values in the bag.
> +    % NOTE_TO_IMPLEMENTORS The _without_duplicates suffix is redundant.
> +    %
> +:- func to_set(bag(T)) = set(T).
> +:- func to_set_without_duplicates(bag(T)) = set(T).
> +:- pred to_set_without_duplicates(bag(T)::in, set(T)::out) is det.

The suffix versions should be deprecated.

...

>      % Compares the two bags, and returns whether the first bag is a
>      % subset (<), is equal (=), or is a superset (>) of the second.
> +    % Fails if the two bags are incomparable.
> +    %
> +    % Examples:
>      % subset_compare(<, {apple, orange}, {apple, apple, orange}).
>      % subset_compare(=, {apple, orange}, {apple, orange}).
>      % subset_compare(>, {apple, apple, orange}, {apple, orange}).
> @@ -243,6 +297,8 @@
>  :- pred subset_compare(comparison_result::out, bag(T)::in, bag(T)::in)
>      is semidet.

There's another existing issue here: it's a little unusual to have
a semidet comparison predicate -- the ordering of the arguments suggests
that this predicate is intended as such -- so we should at least add
det_subset_compare (e.g. so that it is possible to call list.sort/3 on
lists of bags using the subset ordering).

...

>  %---------------------------------------------------------------------------%
>  %---------------------------------------------------------------------------%
> 
> @@ -303,364 +371,689 @@
>  :- type bag(T)
>      --->    bag(map(T, int)).
> 
> +:- inst empty_list
> +    --->    [].
> +:- inst nonempty_list
> +    --->    [ground | ground].

Why do we need a local definition of the second inst when the list module
already exports non_empty_list/0?  (I would delete both of them from here and
add the inst empty_list/0 to the list module.)

The rest of the diff looks ok.

Julien.



More information about the reviews mailing list