Various folds in the containers package

Duncan Coutts duncan.coutts at googlemail.com
Wed Jun 15 14:43:01 CEST 2011


On Wed, 2011-06-15 at 11:15 +0200, Milan Straka wrote:
> Hi all,
> 
> currently we have the following folds in the containers package:
> Map: fold, foldWithKey, foldrWithKey, foldlWithKey
> Set: fold
> IntMap; fold, foldWithKey
> IntSet: fold
> 
> If the direction (right, left) is not specified, the fold is the right
> fold. So currently we have no left folds (except for the Map) and also
> Map and IntMap are not consistent.

My recommendation is that we add all four folds:

foldr, foldl'
foldl, foldr'

Don't get confused with thinking about the "direction". Direction is an
implementation issue (albeit an important one). As you know, the 'l' and
'r' in foldl and foldr are not direction but the left or right
bracketing of the operations.

left bracketing:  ((0 + x_0) + x_1) + x_2
right bracketing: x_0 + (x_1 + (x_2 + 0))

Then the strictness is whether we reduce to WHNF before applying the
operator.

So I think those are the appropriate function names and abstract
definitions, because they correspond to what we're all used to with
lists. The implicit order of the order of the set/map keys, low to high.

Now, when it comes to implementation the direction is important. The
foldr and foldl' functions are best implemented as forwards/ascending
traversals while foldl and foldr' are best implemented as
backwards/descending traversals.

In particular note that we can write things like:

biggest = foldl (\y x -> x) undefined

and evaluate it in O(log n) time. We get "early exit" behaviour.

So by having all four traversals we cover the use cases where people
want folds that start "from the back" (thinking about it operationally).

>    The Foldable module exports foldl' and foldr', which use foldr, foldl
>    respectively, but needs some intermediate memory (it creates a thunk
>    for every node of the structure). Apart from that, this does not
>    cover the *WithKey variants as in b).

This is unfortunate. For data structures with equal access to all
elements (arrays, map/set etc) we can implement foldl' and foldr'
directly and more efficiently.

> Personally I would add foldr, foldl, foldlWithKey, foldrWithKey and
> specialised foldr, foldl implementations in the Foldable classes.
> I am not sure about the strict folds -- I used an equivalent of the
> foldr' from the Foldable module in GHC and it was reasonable fast.
> 
> Any oppinions?

So I suggest all four folds. They are all useful and can all be
implemented efficiently.

Perhaps you need the withKey variety too. Do provide a Foldable
instance, and perhaps later we can lobby for foldl' and foldr' to be
made members of the Foldable class rather than fixed definitions in
terms of foldl and foldr (bytestring, vector and text could benefit from
this too).

Duncan




More information about the Libraries mailing list