[m-rev.] for review: Add take_while and drop_while to the list module

Peter Wang novalazy at gmail.com
Thu Apr 21 23:09:25 AEST 2016


On Thu, 21 Apr 2016 17:09:07 +1000, Paul Bone <paul at bone.id.au> wrote:
> 
> Here's the updated diff.  I've fixed the doc comment for drop_while, renamed
> take_while/4 to split_while/4, and moved it and the deprecated takewhile/4
> so that they're after the other split predicates but before the take
> predicates.  I think this a better name than take_while, and a
> re-arrangement to put predicates near to other relevant ones.

Hi Paul,

I disagree.  take_while is the better name.  Repeatedly "take" the head
of the list "while" this condition is true, and optionally return the
rest.

In split_list/split_upto, "split" means to split a list into a prefix
and suffix.  "split_while" suggests repeatedly splitting a list into a
prefix and suffix (not necessarily head and tail).  It's unclear what
that operation would be.

> diff --git a/NEWS b/NEWS
> index c269b21..313e4a9 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -280,6 +280,14 @@ Changes to the Mercury standard library:
>  
>     - reverse_prepend/2
>     - reverse_prepend/3
> +   - take_while/3
> +   - take_while/2
> +   - drop_while/3
> +   - drop_while/2
> +   - split_while/4
> +
> +* The dropwhile/4 predicate has been deprecated in the list module,
> +  split_while/4 can be used instead.

takewhile/4

> diff --git a/library/list.m b/library/list.m
> index 9565434..a90f95b 100644
> --- a/library/list.m
> +++ b/library/list.m
> @@ -230,6 +230,22 @@
>  :- pred split_upto(int::in, list(T)::in, list(T)::out, list(T)::out)
>      is det.
>  
> +    % split_while(Predicate, List, UptoList, AfterList) takes a
> +    % closure with one input argument, and calls it on successive members
> +    % of List as long as the calls succeed. The elements for which
> +    % the call succeeds are placed in UptoList and the first element for
> +    % which the call fails, and all the remaining elements of List are
> +    % placed in AfterList.
> +    %
> +:- pred split_while(pred(T)::in(pred(in) is semidet), list(T)::in,
> +    list(T)::out, list(T)::out) is det.

I see that's the old description but it's very operational.
The order of UptoList is unconstrained.  It could be clearer
about the AfterList = [] case.

Here's another attempt:

    take_while(Pred, List, Start, End):

    List = Start ++ End.  Start is the longest prefix of List
    where Pred succeeds for every element in Start.
    End is the remainder of the list.

> +    % takewhile/4 is the old name for split_while/4.
> +    %
> +:- pragma obsolete(takewhile/4).
> +:- pred takewhile(pred(T)::in(pred(in) is semidet), list(T)::in,
> +    list(T)::out, list(T)::out) is det.
> +
>      % take(Len, List, Start):
>      %
>      % `Start' is the first `Len' elements of `List'. Fails if `List' has
> @@ -251,6 +267,15 @@
>  :- pred take_upto(int::in, list(T)::in, list(T)::out) is det.
>  :- func take_upto(int, list(T)) = list(T).
>  
> +    % take_while(Pred, List, Start):
> +    %
> +    % 'Start' is the first elements of 'List' that satisfy 'Pred'.
> +    %

    take_while(Pred, List, Start) :-
	take_while(Pred, List, Start, _End).

or from above: Start is the longest prefix ...

> +:- pred take_while(pred(T)::in(pred(in) is semidet), list(T)::in,
> +    list(T)::out) is det.
> +:- func take_while(pred(T), list(T)) = list(T).
> +:- mode take_while(pred(in) is semidet, in) = out is det.
> +
>      % drop(Len, List, End):
>      %
>      % `End' is the remainder of `List' after removing the first `Len' elements.
> @@ -267,6 +292,16 @@
>      %
>  :- pred det_drop(int::in, list(T)::in, list(T)::out) is det.
>  
> +    % drop_while(Pred, List, End):
> +    %
> +    % Drop items that satisfy 'Pred' from the head of 'List' leaving only
> +    % 'End'.
> +    %

    drop_while(Pred, List, End) :-
	take_while(Pred, List, _Start, End).

or

    End is the remainder of List after removing all the consecutive
    elements from the start of List for which Pred succeeds.

Peter


More information about the reviews mailing list