diff --git a/NEWS.md b/NEWS.md index 0ff3f31f4..150cb58de 100644 --- a/NEWS.md +++ b/NEWS.md @@ -773,6 +773,10 @@ Changes to the Mercury standard library - pred `merge_lists_and_remove_dups/3` - pred `nondet_member/2` - pred `remove_prefix/3` + - pred `replace_nth_element0/4` + - pred `replace_nth_element1/4` + - pred `det_replace_nth_element0/4` + - pred `det_replace_nth_element1/4` - func `take_while_not/2` - pred `take_while_not/3` - pred `take_while_not/4` diff --git a/compiler/input_specialization.m b/compiler/input_specialization.m index 2e28dc882..26327076e 100644 --- a/compiler/input_specialization.m +++ b/compiler/input_specialization.m @@ -71,7 +71,6 @@ :- import_module list. :- import_module map. :- import_module one_or_more. -:- import_module require. %---------------------------------------------------------------------------% @@ -236,38 +235,6 @@ create_input_specialized_proc_infos(ArgNum, ReplaceOrAdd, SpecInsts, SpecProcInfos = [HeadSpecProcInfo | TailSpecProcInfos] ). -%---------------------------------------------------------------------------% - -% XXX I (zs) think these should be in library/list.m. - -:- pred det_replace_nth_element1(int::in, T::in, list(T)::in, list(T)::out) - is det. - -det_replace_nth_element1(N, NewItem, Items0, Items) :- - ( if replace_nth_element1(N, NewItem, Items0, ItemsPrime) then - Items = ItemsPrime - else - unexpected($pred, "index out of range") - ). - -:- pred replace_nth_element1(int::in, T::in, list(T)::in, list(T)::out) - is semidet. - -replace_nth_element1(N, NewItem, Items0, Items) :- - replace_nth_element0(N - 1, NewItem, Items0, Items). - -:- pred replace_nth_element0(int::in, T::in, list(T)::in, list(T)::out) - is semidet. - -replace_nth_element0(N, NewItem, [Item0 | Items0], [Item | Items]) :- - ( if N = 0 then - Item = NewItem, - Items = Items0 - else - Item = Item0, - replace_nth_element0(N - 1, NewItem, Items0, Items) - ). - %---------------------------------------------------------------------------% :- end_module hlds.input_specialization. %---------------------------------------------------------------------------% diff --git a/library/list.m b/library/list.m index 8ccec97f5..703802c5e 100644 --- a/library/list.m +++ b/library/list.m @@ -429,6 +429,12 @@ % Fails if N < 1 or if length of List0 < N. % (Position numbers start from 1.) % + % NOTE: please consider using one of replace_nth_element[01] below, + % since these + % + % - clearly specify how they number the list's elements, and + % - their argument order is suitable for the use of state variables. + % :- pred replace_nth(list(T)::in, int::in, T::in, list(T)::out) is semidet. % det_replace_nth(List0, N, R) = List: @@ -438,9 +444,49 @@ % Throw an exception if either N < 1, or if length of List0 < N. % (Position numbers start from 1.) % + % NOTE: please consider using one of det_replace_nth_element[01] below, + % since these + % + % - clearly specify how they number the list's elements, and + % - their argument order is suitable for the use of state variables. + % :- func det_replace_nth(list(T), int, T) = list(T). :- pred det_replace_nth(list(T)::in, int::in, T::in, list(T)::out) is det. + % replace_nth_element1(N, R, List0, List): + % det_replace_nth_element1(N, R, List0, List): + % + % Succeed if-and-only-if List is List0 with its element #N + % replaced with R. (The first element is element #1.) + % + % If List0 has no element #N, either N < 1, or because + % the length of List0 is less than N, then + % + % - replace_nth_element0 fails, while + % - det_replace_nth_element0 fails throws an exception. + % +:- pred replace_nth_element1(int::in, T::in, list(T)::in, list(T)::out) + is semidet. +:- pred det_replace_nth_element1(int::in, T::in, list(T)::in, list(T)::out) + is det. + + % replace_nth_element0(N, R, List0, List): + % det_replace_nth_element0(N, R, List0, List): + % + % Succeed if-and-only-if List is List0 with its element #N + % replaced with R. (The first element is element #0.) + % + % If List0 has no element #N, either N < 0, or because + % the length of List0 is less than N-1, then + % + % - replace_nth_element0 fails, while + % - det_replace_nth_element0 fails throws an exception. + % +:- pred replace_nth_element0(int::in, T::in, list(T)::in, list(T)::out) + is semidet. +:- pred det_replace_nth_element0(int::in, T::in, list(T)::in, list(T)::out) + is det. + %---------------------------------------------------------------------------% % Lo `..` Hi = [Lo, Lo + 1, ..., Hi] if Lo =< Hi, and [] otherwise. @@ -2783,6 +2829,8 @@ replace_all([X | Xs], From, To, RXs) :- RXs = [X | RXs0] ). +%---------------------% + replace_nth(Xs, N, To, RXs) :- N > 0, list.replace_nth_loop(Xs, N, To, RXs). @@ -2817,6 +2865,36 @@ det_replace_nth(Xs, N, To, RXs) :- "Cannot replace element whose index position is less than 1.") ). +%---------------------% + +replace_nth_element1(N, NewItem, Items0, Items) :- + replace_nth_element0(N - 1, NewItem, Items0, Items). + +det_replace_nth_element1(N, NewItem, Items0, Items) :- + ( if replace_nth_element1(N, NewItem, Items0, ItemsPrime) then + Items = ItemsPrime + else + unexpected($pred, "index out of range") + ). + +replace_nth_element0(N, NewItem, [Item0 | Items0], [Item | Items]) :- + ( if N > 0 then + Item = Item0, + replace_nth_element0(N - 1, NewItem, Items0, Items) + else if N = 0 then + Item = NewItem, + Items = Items0 + else + fail + ). + +det_replace_nth_element0(N, NewItem, Items0, Items) :- + ( if replace_nth_element0(N, NewItem, Items0, ItemsPrime) then + Items = ItemsPrime + else + unexpected($pred, "index out of range") + ). + %---------------------------------------------------------------------------% Lo `..` Hi = List :-