Stack overflow in monoidal fold over large list

First, a bit imports,

import Control.Applicative
import Data.Traversable as T
import Data.Foldable as F
import Data.Monoid

Say I have a functor containing a pair of values,

data Fret a = Fret a a deriving (Show)

instance Functor Fret where fmap f (Fret a b) = Fret (f a) (f b)

instance Applicative Fret where
    pure a = Fret a a
    Fret aa ab <*> Fret ba bb = Fret (aa ba) (ab bb)

instance Monoid a => Monoid (Fret a) where
    mempty = Fret mempty mempty
    a `mappend` b = mappend <$> a <*> b

I have a large list of them,

frets = replicate 10000000 (Fret 1 2)

over which I want to calculate a, for example, the average value

data Average a = Average !Int !a deriving (Read, Show)

instance Num a => Monoid (Average a) where
    mempty = Average 0 0
    Average n a `mappend` Average m b = Average (n+m) (a+b)

runAverage :: Fractional a => Average a -> a
runAverage (Average n a) = a / fromIntegral n

average = Average 1

Here are some potential implementations of this,

average1 = runAverage <$> foldMap (fmap average) frets

average2 = pure (runAverage . mconcat) <*> T.sequenceA (map (pure (Average 1) <*>) frets)

Unfortunately, all this leads to a stack overflow.

Thinking that the problem could be excessive laziness Foldable.foldMap, I tried to implement a more rigorous option.

foldMap' :: (F.Foldable f, Monoid m) => (a -> m) -> f a -> m
foldMap' f = F.foldl' (\m a->mappend m $! f a) mempty

average3 = runAverage <$> foldMap' (fmap average) frets

Unfortunately, this is too crowded.

How can this be done without compromising the clean structure of the approach?

Update

If I build Fretstrict fields , everything works as expected. Check if this works in a larger application.

+5
source share
1 answer

, foldMap , Fret, , foldl (+), thunks, , .

, - , , foldMap

enter image description here

- Frets foldl' foldMap , :

 foldMap' f = F.foldl' (\m -> mappend m . f) mempty

 data Fret a = Fret !a !a

enter image description here

+7

All Articles