[m-rev.] for review: bt_array__map implementation; bsearch last argument type qn

Peter Moulder pmoulder at csse.monash.edu.au
Fri Mar 15 17:05:46 AEDT 2002


It's nice to be able to switch back and forth between array and bt_array
relatively easily.  The minimum index thing is one obvious difference
(all bt_array creation methods take a Low argument; no array creation
methods do).  This isn't a huge issue, just adding to the number of
changes to be done (though beware the High/Size distinction).

A more serious difference is that bt_array currently doesn't have a
`map' predicate/function.  The below patch adds that.

There's also a question on bsearch's last argument and determinism,
whether they should be maybe(int)/det or int/semidet.  It looks as if
it was originally int/semidet in both array and bt_array, and then
array__bsearch was changed (1.32) but not bt_array__bsearch.  Both
modules have a stability comment of medium-low.  Should
bt_array__bsearch be changed to maybe(int)/det ?

Currently I have only a in/out is det mode for the map pred/func, which
is all array__map has.  list__map has several other modes.  Should I add
any of them?  Perhaps just a in/out is semidet mode?

pjm.


Estimated hours taken: 4

library/bt_array.m:
	New `bt_array__map/3' predicate and `bt_array__map/2' function.
	Documentation additions & changes.
tests/general/array.m:
tests/general/array.exp:
	Test array__map and bt_array__map predicates.

Index: library/bt_array.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/bt_array.m,v
retrieving revision 1.9
diff -d -u -r1.9 bt_array.m
--- library/bt_array.m	13 Dec 2000 00:00:39 -0000	1.9
+++ library/bt_array.m	15 Mar 2002 06:00:05 -0000
@@ -33,15 +33,15 @@
 
 %-----------------------------------------------------------------------------%
 
-	% bt_array__init(Low, Array) creates a bt_array of size zero
-	% starting at index Low.
+	% bt_array__make_empty_array(Low, Array) creates a bt_array of size
+	% zero starting at index Low.
 :- pred bt_array__make_empty_array(int, bt_array(T)).
 :- mode bt_array__make_empty_array(in, out) is det.
 
 :- func bt_array__make_empty_array(int) = bt_array(T).
 
-	% bt_array__init creates a bt_array with bounds from Low to High,
-	% with each element initialized to Init.
+	% bt_array__init(Low, High, Init, Array) creates a bt_array with bounds
+	% from Low to High, with each element initialized to Init.
 :- pred bt_array__init(int, int, T, bt_array(T)).
 :- mode bt_array__init(in, in, in, out) is det. % want a bt_array_skeleton?
 
@@ -170,9 +170,23 @@
 	% order.  Fails if the element is not present.  If the
 	% element to be found appears multiple times, the index of
 	% the first occurrence is returned.
+	% (Note: the last argument is an int rather than maybe(int) as in
+	% array__bsearch.  XXX: The discrepancy should probably be removed.
+	% Both modules have Stability: medium-low.  It appears that int/semidet
+	% was the original behavior, based on the `Fails if ...' comment still
+	% present in array__bsearch.  So should probably change this to
+	% maybe(int)/det.)
 :- pred bt_array__bsearch(bt_array(T), T, pred(T, T, comparison_result), int).
 :- mode bt_array__bsearch(in, in, pred(in, in, out) is det, out) is semidet.
 
+	% bt_array__map(Closure, OldArray, NewArray) applys `Closure' to
+	% each of the elements of `OldArray' to create `NewArray'.
+:- pred bt_array__map(pred(T1, T2), bt_array(T1), bt_array(T2)).
+:- mode bt_array__map(pred(in, out) is det, in, out) is det.
+
+:- func bt_array__map(func(T1) = T2, bt_array(T1)) = bt_array(T2).
+:- mode bt_array__map(func(in) = out is det, in) = out is det.
+
 	% Field selection for arrays.
 	% Array ^ elem(Index) = bt_array__lookup(Array, Index).
 :- func bt_array__elem(int, bt_array(T)) = T.
@@ -445,6 +459,15 @@
 	).
 
 %-----------------------------------------------------------------------------%
+
+bt_array__map(Pred, bt_array(Low, High, OldRaList), bt_array(Low, High, NewRaList)):-
+	ra_list_map(Pred, OldRaList, NewRaList).
+
+bt_array__map(Func, OldArray) = NewArray :-
+	Pred = ( pred(X::in, Y::out) is det :- Y = Func(X) ),
+	bt_array__map(Pred, OldArray, NewArray).
+
+%-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
 % This is a perfect application for submodules, but Mercury doesn't have
@@ -484,6 +507,12 @@
 
 %-----------------------------------------------------------------------------%
 
+	% Position (for both lookup and update) is specified as a non-negative
+	% integer where 0 indicates the head.
+	%
+	% lookup and update each fail if the specified position is negative or
+	% >= length.
+
 :- pred ra_list_lookup(int, ra_list(T), T).
 :- mode ra_list_lookup(in, in, out) is semidet.
 
@@ -492,6 +521,20 @@
 
 %-----------------------------------------------------------------------------%
 
+	% Discard the N head-most elements: ra_list_drop(N, Big, Small) is true
+	% iff Big contains at least N elements and Small is the same as Big
+	% except without the head-most N elements.  (Unless N<0, in which case
+	% the behavior in the current implementation is as for N=0.  Perhaps
+	% should instead call error for N<0.)
+	%
+	% Declaratively equivalent to:
+	%   ra_list_drop(N, Big, Small):-
+	%     (N =< 0 ->
+	%	Small = Big
+	%     ;
+	%	ra_list_tail(Big, Tail),
+	%	ra_list_drop(N - 1, Tail, Small)
+	%     ).
 :- pred ra_list_drop(int, ra_list(T), ra_list(T)).
 :- mode ra_list_drop(in, in, out) is semidet.
 
@@ -552,8 +595,13 @@
 :- pragma inline(ra_list_lookup/3).
 
 ra_list_lookup(I, List, X) :-
-	I >= 0,
-	ra_list_lookup_2(I, List, X).
+	% Must test before calling ra_list_lookup_2 to avoid infinite loop
+	% hence using `if' rather than simple conjunction, which has no
+	% order guarantee in the default, strict-commutative, semantics.
+	I >= 0 ->
+		ra_list_lookup_2(I, List, X)
+	;
+		fail.
 
 :- pred ra_list_lookup_2(int, ra_list(T), T).
 :- mode ra_list_lookup_2(in, in, out) is semidet.
@@ -628,13 +676,34 @@
 
 %-----------------------------------------------------------------------------%
 
+:- pred ra_list_map(pred(T1, T2), ra_list(T1), ra_list(T2)).
+:- mode ra_list_map(pred(in, out) is det, in, out) is det.
+
+ra_list_map(_Closure, nil, nil).
+ra_list_map(Closure, cons(Size, A_BT, A_Rest), cons(Size, B_BT, B_Rest)) :-
+	ra_list_bintree_map(Closure, A_BT, B_BT),
+	ra_list_map(Closure, A_Rest, B_Rest).
+
+:- pred ra_list_bintree_map(pred(T1, T2), ra_list_bintree(T1), ra_list_bintree(T2)).
+:- mode ra_list_bintree_map(pred(in, out) is det, in, out) is det.
+
+ra_list_bintree_map(Closure, leaf(A), leaf(B)):-
+	call(Closure, A, B).
+
+ra_list_bintree_map(Closure, node(A_X, A_T1, A_T2), node(B_X, B_T1, B_T2)):-
+	call(Closure, A_X, B_X),
+	ra_list_bintree_map(Closure, A_T1, B_T1),
+	ra_list_bintree_map(Closure, A_T2, B_T2).
+
+%-----------------------------------------------------------------------------%
+
 ra_list_drop(N, As, Bs) :-
 	(
 		N > 0
 	->
-		As = cons(Size, _, Cs),
-		( Size < N ->
-			N1 is N - Size,
+		As = cons(AHeadTreeSize, _AHeadTree, Cs),
+		( AHeadTreeSize =< N ->
+			N1 is N - AHeadTreeSize,
 			ra_list_drop(N1, Cs, Bs)
 		;
 			ra_list_slow_drop(N, As, Bs)
Index: tests/general/array_test.m
===================================================================
RCS file: /home/mercury1/repository/tests/general/array_test.m,v
retrieving revision 1.4
diff -d -u -r1.4 array_test.m
--- tests/general/array_test.m	24 Apr 2001 03:59:13 -0000	1.4
+++ tests/general/array_test.m	15 Mar 2002 06:00:05 -0000
@@ -50,6 +50,9 @@
 	{ A5 = array__sort(array(list__reverse(1 `..` 10))) },
 	{ array__to_list(A5, As5) },
 	write_message_int_list("A5: ", As5),
+	{ array__map((pred(X::in, X2::out) is det:- X2 is X * X), A5, A6) },
+	{ array__to_list(A6, As6) },
+	write_message_int_list("A6: ", As6),
 
 	{ bt_array__from_list(0, Xs, B0) },
 	{ bt_array__to_list(B0, Bs0) },
@@ -78,6 +81,9 @@
 	{ bt_array__shrink(B2, 0, 9, B3) },
 	{ bt_array__to_list(B3, Bs3) },
 	write_message_int_list("B3: ", Bs3),
+	{ bt_array__map((pred(X::in, X2::out) is det:- X2 is X * X), bt_array(1 `..` 10), B6) },
+	{ bt_array__to_list(B6, Bs6) },
+	write_message_int_list("B6: ", Bs6),
 
 	% Finally, just in case, compare the two implementations.
 	(
@@ -96,6 +102,7 @@
 			As1 = Bs1,
 			As2 = Bs2,
 			As3 = Bs3,
+			As6 = Bs6,
 			As1 = As3,	% Sanity check
 			Bs1 = Bs3	% Sanity check
 		}
Index: tests/general/array_test.exp
===================================================================
RCS file: /home/mercury1/repository/tests/general/array_test.exp,v
retrieving revision 1.2
diff -d -u -r1.2 array_test.exp
--- tests/general/array_test.exp	20 Feb 2001 10:42:17 -0000	1.2
+++ tests/general/array_test.exp	15 Mar 2002 06:00:05 -0000
@@ -10,6 +10,7 @@
 A3: [1, 2, 3, 4, 5, 6, 7, 8, 100, 10]
 A4: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 A5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+A6: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
 B0: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
 BMax0: 9
 BMin0: 0
@@ -20,4 +21,5 @@
 B1: [1, 2, 3, 4, 5, 6, 7, 8, 100, 10]
 B2: [1, 2, 3, 4, 5, 6, 7, 8, 100, 10, 1000, 1000, 1000, 1000, 1000]
 B3: [1, 2, 3, 4, 5, 6, 7, 8, 100, 10]
+B6: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
 Results all match
--------------------------------------------------------------------------
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