[m-rev.] For post-commit review: add more library predicates

Julien Fischer jfischer at opturion.com
Mon Aug 8 21:13:51 AEST 2016


Add some more library predicates.

library/hash_table.m:
     Add fold2/6 and fold3/8.

library/rbtree.m:
     Add foldl2_values/6.

library/assoc_list.m:
     Add the predicate svremove/4, which is like remove/4 but with the
     arguments in an order more conducive to the use of state variable
     notation.  Eventually, we should deprecate the current remove/4
     and re-order its arguments so they match those of the identically
     named predicates for other types that implement the map ADT.

     Do not module qualify clause heads.

NEWS:
      Announce the above.

Julien.

diff --git a/NEWS b/NEWS
index 48df372..ab3b0ea 100644
--- a/NEWS
+++ b/NEWS
@@ -362,9 +362,19 @@ Changes to the Mercury standard library:
     - mktime/1
     - ctime/1

-* The following predicate has been added to the rbtree module:
+* The following predicates have been added to the rbtree module:

     - foldl_values/4
+   - foldl2_values/6
+
+* The following predicates have been added to the hash_table module:
+
+   - fold2/6
+   - fold3/8
+
+* We have added the predicate svremove/4 to the assoc_list module.
+  This like the remove/4 predicate but with its arguments are in
+  an order more conducive to the use of state variable notation.

  Changes to the Mercury compiler:

diff --git a/library/assoc_list.m b/library/assoc_list.m
index 60458d0..008e3e2 100644
--- a/library/assoc_list.m
+++ b/library/assoc_list.m
@@ -76,6 +76,12 @@
  :- pred remove(assoc_list(K, V)::in, K::in, V::out, assoc_list(K, V)::out)
      is semidet.

+    % As above, but with an argument ordering that is more conducive to
+    % the use of state variable notation.
+    %
+:- pred svremove(K::in, V::out, assoc_list(K, V)::in, assoc_list(K, V)::out)
+    is semidet.
+
  :- func map_keys_only(func(K) = L, assoc_list(K, V)) = assoc_list(L, V).
  :- pred map_keys_only(pred(K, L), assoc_list(K, V), assoc_list(L, V)).
  :- mode map_keys_only(pred(in, out) is det, in, out) is det.
@@ -212,17 +218,17 @@

  %---------------------------------------------------------------------------%

-assoc_list.reverse_members(AL1) = AL2 :-
+reverse_members(AL1) = AL2 :-
      assoc_list.reverse_members(AL1, AL2).

-assoc_list.reverse_members([], []).
-assoc_list.reverse_members([K - V | KVs], [V - K | VKs]) :-
+reverse_members([], []).
+reverse_members([K - V | KVs], [V - K | VKs]) :-
      assoc_list.reverse_members(KVs, VKs).

-assoc_list.from_corresponding_lists(Ks, Vs) = AL :-
+from_corresponding_lists(Ks, Vs) = AL :-
      assoc_list.from_corresponding_lists(Ks, Vs, AL).

-assoc_list.from_corresponding_lists(Ks, Vs, KVs) :-
+from_corresponding_lists(Ks, Vs, KVs) :-
      ( if assoc_list.from_corresponding_2(Ks, Vs, KVsPrime) then
          KVs = KVsPrime
      else
@@ -244,29 +250,29 @@ assoc_list.from_corresponding_lists(Ks, Vs, KVs) :-
  :- pred assoc_list.from_corresponding_2(list(K)::in, list(V)::in,
      assoc_list(K,V)::out) is semidet.

-assoc_list.from_corresponding_2([], [], []).
-assoc_list.from_corresponding_2([A | As], [B | Bs], [A - B | ABs]) :-
+from_corresponding_2([], [], []).
+from_corresponding_2([A | As], [B | Bs], [A - B | ABs]) :-
      assoc_list.from_corresponding_2(As, Bs, ABs).

-assoc_list.keys(AL) = Ks :-
+keys(AL) = Ks :-
      assoc_list.keys(AL, Ks).

-assoc_list.keys([], []).
-assoc_list.keys([K - _ | KVs], [K | Ks]) :-
+keys([], []).
+keys([K - _ | KVs], [K | Ks]) :-
      assoc_list.keys(KVs, Ks).

-assoc_list.values(AL) = Vs :-
+values(AL) = Vs :-
      assoc_list.values(AL, Vs).

-assoc_list.values([], []).
-assoc_list.values([_ - V | KVs], [V | Vs]) :-
+values([], []).
+values([_ - V | KVs], [V | Vs]) :-
      assoc_list.values(KVs, Vs).

-assoc_list.keys_and_values([], [], []).
-assoc_list.keys_and_values([K - V | KVs], [K | Ks], [V | Vs]) :-
+keys_and_values([], [], []).
+keys_and_values([K - V | KVs], [K | Ks], [V | Vs]) :-
      assoc_list.keys_and_values(KVs, Ks, Vs).

-assoc_list.search([K - V | KVs], Key, Value) :-
+search([K - V | KVs], Key, Value) :-
      ( if K = Key then
          Value = V
      else
@@ -283,7 +289,7 @@ AL ^ det_elem(K) = V :-
          report_lookup_error("assoc_list.det_elem: key not found", K)
      ).

-assoc_list.remove([K - V | KVs], Key, Value, Filtered) :-
+remove([K - V | KVs], Key, Value, Filtered) :-
      ( if K = Key then
          Value = V,
          Filtered = KVs
@@ -292,38 +298,41 @@ assoc_list.remove([K - V | KVs], Key, Value, Filtered) :-
          Filtered = [K - V | FilteredTail]
      ).

-assoc_list.map_keys_only(_P, [], []).
-assoc_list.map_keys_only(P, [K0 - V | KVs0], [K - V | KVs]) :-
+svremove(Key, Value, !AL) :-
+    assoc_list.remove(!.AL, Key, Value, !:AL).
+
+map_keys_only(_P, [], []).
+map_keys_only(P, [K0 - V | KVs0], [K - V | KVs]) :-
      P(K0, K),
      assoc_list.map_keys_only(P, KVs0, KVs).

-assoc_list.map_keys_only(_F, []) = [].
-assoc_list.map_keys_only(F, [K0 - V | KVs0]) = [K - V | KVs] :-
+map_keys_only(_F, []) = [].
+map_keys_only(F, [K0 - V | KVs0]) = [K - V | KVs] :-
      K = F(K0),
      KVs = assoc_list.map_keys_only(F, KVs0).

-assoc_list.map_values_only(_P, [], []).
-assoc_list.map_values_only(P, [K - V0 | KVs0], [K - V | KVs]) :-
+map_values_only(_P, [], []).
+map_values_only(P, [K - V0 | KVs0], [K - V | KVs]) :-
      P(V0, V),
      assoc_list.map_values_only(P, KVs0, KVs).

-assoc_list.map_values_only(_F, []) = [].
-assoc_list.map_values_only(F, [K - V0 | KVs0]) = [K - V | KVs] :-
+map_values_only(_F, []) = [].
+map_values_only(F, [K - V0 | KVs0]) = [K - V | KVs] :-
      V = F(V0),
      KVs = assoc_list.map_values_only(F, KVs0).

-assoc_list.map_values(_P, [], []).
-assoc_list.map_values(P, [K - V0 | KVs0], [K - V | KVs]) :-
+map_values(_P, [], []).
+map_values(P, [K - V0 | KVs0], [K - V | KVs]) :-
      P(K, V0, V),
      assoc_list.map_values(P, KVs0, KVs).

-assoc_list.map_values(_F, []) = [].
-assoc_list.map_values(F, [K - V0 | KVs0]) = [K - V | KVs] :-
+map_values(_F, []) = [].
+map_values(F, [K - V0 | KVs0]) = [K - V | KVs] :-
      V = F(K, V0),
      KVs = assoc_list.map_values(F, KVs0).

-assoc_list.filter(_, [],  []).
-assoc_list.filter(P, [HK - HV | T], True) :-
+filter(_, [],  []).
+filter(P, [HK - HV | T], True) :-
      ( if P(HK) then
          assoc_list.filter(P, T, TrueTail),
          True = [HK - HV | TrueTail]
@@ -331,11 +340,11 @@ assoc_list.filter(P, [HK - HV | T], True) :-
          assoc_list.filter(P, T, True)
      ).

-assoc_list.filter(P, List) = Trues :-
+filter(P, List) = Trues :-
      assoc_list.filter(P, List, Trues).

-assoc_list.negated_filter(_, [],  []).
-assoc_list.negated_filter(P, [HK - HV | T], False) :-
+negated_filter(_, [],  []).
+negated_filter(P, [HK - HV | T], False) :-
      ( if P(HK) then
          assoc_list.negated_filter(P, T, False)
      else
@@ -343,11 +352,11 @@ assoc_list.negated_filter(P, [HK - HV | T], False) :-
          False = [HK - HV | FalseTail]
      ).

-assoc_list.negated_filter(P, List) = Falses :-
+negated_filter(P, List) = Falses :-
      assoc_list.negated_filter(P, List, Falses).

-assoc_list.filter(_, [],  [], []).
-assoc_list.filter(P, [HK - HV | T], True, False) :-
+filter(_, [],  [], []).
+filter(P, [HK - HV | T], True, False) :-
      ( if P(HK) then
          assoc_list.filter(P, T, TrueTail, False),
          True = [HK - HV | TrueTail]
@@ -356,13 +365,13 @@ assoc_list.filter(P, [HK - HV | T], True, False) :-
          False = [HK - HV | FalseTail]
      ).

-assoc_list.merge(As, Bs) = ABs :-
+merge(As, Bs) = ABs :-
      assoc_list.merge(As, Bs, ABs).

-assoc_list.merge([], [], []).
-assoc_list.merge([A | As], [], [A | As]).
-assoc_list.merge([], [B | Bs], [B | Bs]).
-assoc_list.merge([A | As], [B | Bs], Cs) :-
+merge([], [], []).
+merge([A | As], [], [A | As]).
+merge([], [B | Bs], [B | Bs]).
+merge([A | As], [B | Bs], Cs) :-
      ( if
          A = AK - _AV,
          B = BK - _BV,
@@ -376,26 +385,26 @@ assoc_list.merge([A | As], [B | Bs], Cs) :-
          Cs = [A | Cs0]
      ).

-assoc_list.foldl_keys(_, [], !Acc).
-assoc_list.foldl_keys(P, [KV | KVs], !Acc) :-
+foldl_keys(_, [], !Acc).
+foldl_keys(P, [KV | KVs], !Acc) :-
      KV = K - _V,
      P(K, !Acc),
      assoc_list.foldl_keys(P, KVs, !Acc).

-assoc_list.foldl_values(_, [], !Acc).
-assoc_list.foldl_values(P, [KV | KVs], !Acc) :-
+foldl_values(_, [], !Acc).
+foldl_values(P, [KV | KVs], !Acc) :-
      KV = _K - V,
      P(V, !Acc),
      assoc_list.foldl_values(P, KVs, !Acc).

-assoc_list.foldl2_values(_, [], !Acc1, !Acc2).
-assoc_list.foldl2_values(P, [KV | KVs], !Acc1, !Acc2) :-
+foldl2_values(_, [], !Acc1, !Acc2).
+foldl2_values(P, [KV | KVs], !Acc1, !Acc2) :-
      KV = _K - V,
      P(V, !Acc1, !Acc2),
      assoc_list.foldl2_values(P, KVs, !Acc1, !Acc2).

-assoc_list.foldl3_values(_, [], !Acc1, !Acc2, !Acc3).
-assoc_list.foldl3_values(P, [KV | KVs], !Acc1, !Acc2, !Acc3) :-
+foldl3_values(_, [], !Acc1, !Acc2, !Acc3).
+foldl3_values(P, [KV | KVs], !Acc1, !Acc2, !Acc3) :-
      KV = _K - V,
      P(V, !Acc1, !Acc2, !Acc3),
      assoc_list.foldl3_values(P, KVs, !Acc1, !Acc2, !Acc3).
diff --git a/library/hash_table.m b/library/hash_table.m
index 1e8e5c0..1791d9a 100644
--- a/library/hash_table.m
+++ b/library/hash_table.m
@@ -215,7 +215,7 @@

      % Fold a predicate over the key-value bindings in a hash table.
      %
-:- pred fold(pred(K, V, T, T), hash_table(K, V), T, T).
+:- pred fold(pred(K, V, A, A), hash_table(K, V), A, A).
  :- mode fold(in(pred(in, in, in, out) is det), hash_table_ui,
      in, out) is det.
  :- mode fold(in(pred(in, in, mdi, muo) is det), hash_table_ui,
@@ -229,6 +229,35 @@
  :- mode fold(in(pred(in, in, di, uo) is semidet), hash_table_ui,
      di, uo) is semidet.

+:- pred fold2(pred(K, V, A, A, B, B), hash_table(K, V), A, A, B, B).
+:- mode fold2(in(pred(in, in, in, out, in, out) is det), hash_table_ui,
+    in, out, in, out) is det.
+:- mode fold2(in(pred(in, in, in, out, mdi, muo) is det), hash_table_ui,
+    in, out, mdi, muo) is det.
+:- mode fold2(in(pred(in, in, in, out, di, uo) is det), hash_table_ui,
+    in, out, di, uo) is det.
+:- mode fold2(in(pred(in, in, in, out, in, out) is semidet), hash_table_ui,
+    in, out, in, out) is semidet.
+:- mode fold2(in(pred(in, in, in, out, mdi, muo) is semidet), hash_table_ui,
+    in, out, mdi, muo) is semidet.
+:- mode fold2(in(pred(in, in, in, out, di, uo) is semidet), hash_table_ui,
+    in, out, di, uo) is semidet.
+
+:- pred fold3(pred(K, V, A, A, B, B, C, C), hash_table(K, V), A, A, B, B,
+    C, C).
+:- mode fold3(in(pred(in, in, in, out, in, out, in, out) is det),
+    hash_table_ui, in, out, in, out, in, out) is det.
+:- mode fold3(in(pred(in, in, in, out, in, out, mdi, muo) is det),
+    hash_table_ui, in, out, in, out, mdi, muo) is det.
+:- mode fold3(in(pred(in, in, in, out, in, out, di, uo) is det),
+    hash_table_ui, in, out, in, out, di, uo) is det.
+:- mode fold3(in(pred(in, in, in, out, in, out, in, out) is semidet),
+    hash_table_ui, in, out, in, out, in, out) is semidet.
+:- mode fold3(in(pred(in, in, in, out, in, out, mdi, muo) is semidet),
+    hash_table_ui, in, out, in, out, mdi, muo) is semidet.
+:- mode fold3(in(pred(in, in, in, out, in, out, di, uo) is semidet),
+    hash_table_ui, in, out, in, out, di, uo) is semidet.
+
  %---------------------------------------------------------------------------%
  %---------------------------------------------------------------------------%

@@ -758,7 +787,7 @@ fold_f(F, List, A0, A) :-
  fold(P, HT, !A) :-
      foldl(fold_p(P), HT ^ buckets, !A).

-:- pred fold_p(pred(K, V, T, T), hash_table_alist(K, V), T, T).
+:- pred fold_p(pred(K, V, A, A), hash_table_alist(K, V), A, A).
  :- mode fold_p(pred(in, in, in, out) is det, in, in, out) is det.
  :- mode fold_p(pred(in, in, mdi, muo) is det, in, mdi, muo) is det.
  :- mode fold_p(pred(in, in, di, uo) is det, in, di, uo) is det.
@@ -779,5 +808,68 @@ fold_p(P, List, !A) :-
      ).

  %---------------------------------------------------------------------------%
+
+fold2(P, HT, !A, !B) :-
+    foldl2(fold2_p(P), HT ^ buckets, !A, !B).
+
+:- pred fold2_p(pred(K, V, A, A, B, B), hash_table_alist(K, V), A, A, B, B).
+:- mode fold2_p(pred(in, in, in, out, in, out) is det, in, in, out,
+    in, out) is det.
+:- mode fold2_p(pred(in, in, in, out, mdi, muo) is det, in, in, out,
+    mdi, muo) is det.
+:- mode fold2_p(pred(in, in, in, out, di, uo) is det, in, in, out,
+    di, uo) is det.
+:- mode fold2_p(pred(in, in, in, out, in, out) is semidet, in, in, out,
+    in, out) is semidet.
+:- mode fold2_p(pred(in, in, in, out, mdi, muo) is semidet, in,in, out,
+    mdi, muo) is semidet.
+:- mode fold2_p(pred(in, in, in, out, di, uo) is semidet, in, in, out,
+    di, uo) is semidet.
+
+fold2_p(P, List, !A, !B) :-
+    (
+        List = ht_nil
+    ;
+        List = ht_single(K, V),
+        P(K, V, !A, !B)
+    ;
+        List = ht_cons(K, V, KVs),
+        P(K, V, !A, !B),
+        fold2_p(P, KVs, !A, !B)
+    ).
+
+%---------------------------------------------------------------------------%
+
+fold3(P, HT, !A, !B, !C) :-
+    foldl3(fold3_p(P), HT ^ buckets, !A, !B, !C).
+
+:- pred fold3_p(pred(K, V, A, A, B, B, C, C), hash_table_alist(K, V),
+    A, A, B, B, C, C).
+:- mode fold3_p(pred(in, in, in, out, in, out, in, out) is det, in,
+    in, out, in, out, in, out) is det.
+:- mode fold3_p(pred(in, in, in, out, in, out, mdi, muo) is det, in,
+    in, out, in, out, mdi, muo) is det.
+:- mode fold3_p(pred(in, in, in, out, in, out, di, uo) is det, in,
+    in, out, in, out, di, uo) is det.
+:- mode fold3_p(pred(in, in, in, out, in, out, in, out) is semidet, in,
+    in, out, in, out, in, out) is semidet.
+:- mode fold3_p(pred(in, in, in, out, in, out, mdi, muo) is semidet, in,
+    in, out, in, out, mdi, muo) is semidet.
+:- mode fold3_p(pred(in, in, in, out, in, out, di, uo) is semidet, in,
+    in, out, in, out, di, uo) is semidet.
+
+fold3_p(P, List, !A, !B, !C) :-
+    (
+        List = ht_nil
+    ;
+        List = ht_single(K, V),
+        P(K, V, !A, !B, !C)
+    ;
+        List = ht_cons(K, V, KVs),
+        P(K, V, !A, !B, !C),
+        fold3_p(P, KVs, !A, !B, !C)
+    ).
+
+%---------------------------------------------------------------------------%
  :- end_module hash_table.
  %---------------------------------------------------------------------------%
diff --git a/library/rbtree.m b/library/rbtree.m
index bfc9bc5..eb2b554 100644
--- a/library/rbtree.m
+++ b/library/rbtree.m
@@ -230,6 +230,20 @@
  :- mode foldl_values(pred(in, mdi, muo) is semidet, in, mdi, muo) is semidet.
  :- mode foldl_values(pred(in, di, uo) is semidet, in, di, uo) is semidet.

+:- pred foldl2_values(pred(V, A, A, B, B), rbtree(K, V), A, A, B, B).
+:- mode foldl2_values(pred(in, in, out, in, out) is det, in, in, out,
+    in, out) is det.
+:- mode foldl2_values(pred(in, in, out, mdi, muo) is det, in, in, out,
+    mdi, muo) is det.
+:- mode foldl2_values(pred(in, in, out, di, uo) is det, in, in, out,
+    di, uo) is det.
+:- mode foldl2_values(pred(in, in, out, in, out) is semidet, in, in, out,
+    in, out) is semidet.
+:- mode foldl2_values(pred(in, in, out, mdi, muo) is semidet, in, in, out,
+    mdi, muo) is semidet.
+:- mode foldl2_values(pred(in, in, out, di, uo) is semidet, in, in, out,
+    di, uo) is semidet.
+
  :- func map_values(func(K, V) = W, rbtree(K, V)) = rbtree(K, W).
  :- pred map_values(pred(K, V, W), rbtree(K, V), rbtree(K, W)).
  :- mode map_values(pred(in, in, out) is det, in, out) is det.
@@ -1113,6 +1127,18 @@ foldl_values(Pred, black(_K, V, Left, Right), !Acc) :-

  %---------------------------------------------------------------------------%

+foldl2_values(_Pred, empty, !Acc1, !Acc2).
+foldl2_values(Pred, red(_K, V, Left, Right), !Acc1, !Acc2) :-
+    rbtree.foldl2_values(Pred, Left, !Acc1, !Acc2),
+    Pred(V, !Acc1, !Acc2),
+    rbtree.foldl2_values(Pred, Right, !Acc1, !Acc2).
+foldl2_values(Pred, black(_K, V, Left, Right), !Acc1, !Acc2) :-
+    rbtree.foldl2_values(Pred, Left, !Acc1, !Acc2),
+    Pred(V, !Acc1, !Acc2),
+    rbtree.foldl2_values(Pred, Right, !Acc1, !Acc2).
+
+%---------------------------------------------------------------------------%
+
  map_values(F, T1) = T2 :-
      P = ( pred(X::in, Y::in, Z::out) is det :- Z = F(X, Y) ),
      rbtree.map_values(P, T1, T2).


More information about the reviews mailing list