Roundup on proposal 3671 [was: Re: Proposal (Trac ticket #3671): Add takeRec, genericTakeRec and spanRec to Data.List]

Christian Maeder Christian.Maeder at
Wed Nov 25 11:45:16 EST 2009

Philip K.F. Hölzenspies schrieb:
> Dear Christian, et al.
> Thanks for the summary, Christian. I've given some detailed comments
> below, but I'll give the gist here.
> The ticket has indeed moved on quite a bit. Some more expressive
> functions were proposed that weren't part of the ticket, but that maybe
> should have been. Some of the originally proposed functions can be
> expressed easily in these more expressive ones and, therefore, may not
> be wanted inclusions any more.
> I suggest we get everyone to +1 or -1 on the following list of possible
> new inclusions (where the slash-separated list of names all represent
> the same function - for +1s also indicate name preference):
> - takeRec / splitAts / groupsOf / segmentsOf :: Int -> [a] -> [[a]]

in such a function is called
"chunk" and "splitEvery". My preference would be "chunks", but
"splitAts", "splits", or "segmentsOf" is fine, too.

> - genericTakeRec / genericSplitAts / genericGroupsOf /
> genericSegmentsOf :: Integral i => i -> [a] -> [[a]]

How should the above functions behave for the corner case of the
number being less than 1? I see several options:

  1. abort (my preference)
  2. return the empty list
  3. return the singleton list of the input (non-intuitive)
  4. return the infinite list of empty lists

> - spanRec / spans :: (a -> Bool) -> [a] -> [[a]]
> - breakRec / breaks :: (a -> Bool) -> [a] -> [[a]]

in there is a function called
splitWhen. The main point to clarify is how delimiters (determined by
the input predicate for breaks) influence the output list.
 1. Should delimiters be part of the output?
 2. Should consecutive delimiters produce separate sublists
 3. Should empty lists be elements of the result list
 4. If yes, should leading or trailing delimiters produce leading or
trailing empty list elements.

> - runs :: (a -> a -> Bool) -> [a] -> [[a]]

maybe under a different name: "runBy"

> - run :: (a -> a -> Bool) -> [a] -> ([a],[a])

"runs" is similar to "groupBy", therefore I proposed "runBy" for "runs".

For groupBy we have no function that's splits off the first group only,
therefore (I think) we don't need one for the first run, too.
Furthermore, the relation between "runBy" und "run" would be different
from the one between "groupBy" and "group".

An alternative would be to use "firstRunBy" for "run" and also add a
function "firstGroupBy".

> - replace :: Eq a => [a] -> [a] -> [a] -> [a]

Here also the corner case needs to be clarified, what should happen, if
the empty list should be replaced.

> - replaceBy :: ([a] -> (b, [a])) -> [a] -> [b]

As a recursion scheme that is comparable to iterate or replicate the
name is too special. I also just notice that a more general recursion
scheme would be:

  recurse :: (a -> (b, Maybe a)) -> a -> [b]
or the given
  unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

unfoldr could be used directly in a similar way than my replaceBy. In fact:

  replaceBy splt =
    unfoldr (\ l -> if null l then Nothing else
      Just (splt l))

So replaceBy is not really needed!

> The implementations of the chosen functions should, in my mind, be based
> on profiling results.


> As an open procedural question: can a proposal track ticket be
> obsolidated by a new ticket? What is the common procedure for revising a
> proposal?

I actually don't know. But I would recommend to close this ticket and
open a new one (or several new ones) if some agreement is achieved (or
none without agreement).

Cheers Christian

More information about the Libraries mailing list