module Main where

import qualified Control.MapReduce.Simple      as MR
import qualified Control.Foldl                 as FL

ints n = take n [1 ..]

multipleOf n x = (x `mod` n) == 0

onlyEven = MR.filterUnpack even -- a filter

andTwice x = [x, 2 * x]  -- a "melt"

withTwice :: MR.Unpack Int Int
withTwice = MR.Unpack andTwice

groupByMultOf3 = MR.assign (multipleOf 3) realToFrac

-- An example using the function version
addAll :: (Foldable f, Num a) => f a -> a
addAll = FL.fold FL.sum


reduceSum = MR.foldAndLabel FL.sum ((,))
reduceSum' = MR.processAndLabel addAll (,)
reduceMean = MR.foldAndLabel FL.mean ((,))

  sum of all even ints , grouped by whether or not they are mutliples of 3
sumsF = MR.mapReduceFold onlyEven groupByMultOf3 reduceSum
sumsF' = MR.mapReduceFold onlyEven groupByMultOf3 reduceSum'

  mean of all even ints , grouped by whether or not they are mutliples of 3
meansF = MR.mapReduceFold onlyEven groupByMultOf3 reduceMean

-- loop over initial list once but group each time
sumsAndMeansF = (,) <$> sumsF <*> meansF

-- loop over initial list once and group only once.
sumAndMeanEachF =
  MR.mapReduceFold onlyEven groupByMultOf3 ((,) <$> reduceSum <*> reduceMean)

  sum and mean of all ints -- and twice each int -- grouped by whether or not they are multiples of 3 .
sumAndMeanWithTwiceF =
  MR.mapReduceFold withTwice groupByMultOf3 ((,) <$> reduceSum <*> reduceMean)



 We combine all the folds we want to do into one fold .   So we loop over the input list only once here . 
 We group it for each fold .   But the last two ,  and sumAndMeanWithTwice shows how we can avoid that as well . 

We combine all the folds we want to do into one fold.  So we loop over the input list only once here.
We group it for each fold.  But the last two, sumAndMeanEach and sumAndMeanWithTwice shows how we can avoid that as well.
-}

main :: IO ()
main = do
  let (s, s', m, sm, sme, smd) = MR.fold
        (   (,,,,,)
        <$> sumsF
        <*> sumsF'
        <*> meansF
        <*> sumsAndMeansF
        <*> sumAndMeanEachF
        <*> sumAndMeanWithTwiceF
        )
        (ints 100)
  putStrLn $ "Sums: " ++ show s
  putStrLn $ "Sums': " ++ show s'
  putStrLn $ "Means: " ++ show m
  putStrLn $ "Sums & Means: " ++ show sm
  putStrLn $ "Sum & Mean of each: " ++ show sme
  putStrLn $ "Sum & Mean of all plus doubles: " ++ show smd


  Output : 

 Sums : [ ( False,1734.0),(True,816.0 ) ] 
 Sums ' : [ ( False,1734.0),(True,816.0 ) ] 
 Means : [ ( False,51.0),(True,51.0 ) ] 
 Sums & Means : ( [ ( False,1734.0),(True,816.0)],[(False,51.0),(True,51.0 ) ] ) 
 Sum & Mean of each : [ ( ( False,1734.0),(False,51.0)),((True,816.0),(True,51.0 ) ) ] 
 Sum & Mean of all plus doubles : [ ( (  ) ) ] 



Sums: [(False,1734.0),(True,816.0)]
Sums': [(False,1734.0),(True,816.0)]
Means: [(False,51.0),(True,51.0)]
Sums & Means: ([(False,1734.0),(True,816.0)],[(False,51.0),(True,51.0)])
Sum & Mean of each: [((False,1734.0),(False,51.0)),((True,816.0),(True,51.0))]
Sum & Mean of all plus doubles: [((False,10101.0),(False,75.38059701492539)),((True,5049.0),(True,76.5))]

-}

 a filter
 a "melt"
 An example using the function version
 loop over initial list once but group each time
 loop over initial list once and group only once.
 and twice each int -- grouped by whether or not they are multiples of 3 .
module Main where

import qualified Control.MapReduce.Simple      as MR
import qualified Control.Foldl                 as FL

ints n = take n [1 ..]

multipleOf n x = (x `mod` n) == 0



withTwice :: MR.Unpack Int Int
withTwice = MR.Unpack andTwice

groupByMultOf3 = MR.assign (multipleOf 3) realToFrac

addAll :: (Foldable f, Num a) => f a -> a
addAll = FL.fold FL.sum


reduceSum = MR.foldAndLabel FL.sum ((,))
reduceSum' = MR.processAndLabel addAll (,)
reduceMean = MR.foldAndLabel FL.mean ((,))

  sum of all even ints , grouped by whether or not they are mutliples of 3
sumsF = MR.mapReduceFold onlyEven groupByMultOf3 reduceSum
sumsF' = MR.mapReduceFold onlyEven groupByMultOf3 reduceSum'

  mean of all even ints , grouped by whether or not they are mutliples of 3
meansF = MR.mapReduceFold onlyEven groupByMultOf3 reduceMean

sumsAndMeansF = (,) <$> sumsF <*> meansF

sumAndMeanEachF =
  MR.mapReduceFold onlyEven groupByMultOf3 ((,) <$> reduceSum <*> reduceMean)

sumAndMeanWithTwiceF =
  MR.mapReduceFold withTwice groupByMultOf3 ((,) <$> reduceSum <*> reduceMean)



 We combine all the folds we want to do into one fold .   So we loop over the input list only once here . 
 We group it for each fold .   But the last two ,  and sumAndMeanWithTwice shows how we can avoid that as well . 

We combine all the folds we want to do into one fold.  So we loop over the input list only once here.
We group it for each fold.  But the last two, sumAndMeanEach and sumAndMeanWithTwice shows how we can avoid that as well.
-}

main :: IO ()
main = do
  let (s, s', m, sm, sme, smd) = MR.fold
        (   (,,,,,)
        <$> sumsF
        <*> sumsF'
        <*> meansF
        <*> sumsAndMeansF
        <*> sumAndMeanEachF
        <*> sumAndMeanWithTwiceF
        )
        (ints 100)
  putStrLn $ "Sums: " ++ show s
  putStrLn $ "Sums': " ++ show s'
  putStrLn $ "Means: " ++ show m
  putStrLn $ "Sums & Means: " ++ show sm
  putStrLn $ "Sum & Mean of each: " ++ show sme
  putStrLn $ "Sum & Mean of all plus doubles: " ++ show smd


  Output : 

 Sums : [ ( False,1734.0),(True,816.0 ) ] 
 Sums ' : [ ( False,1734.0),(True,816.0 ) ] 
 Means : [ ( False,51.0),(True,51.0 ) ] 
 Sums & Means : ( [ ( False,1734.0),(True,816.0)],[(False,51.0),(True,51.0 ) ] ) 
 Sum & Mean of each : [ ( ( False,1734.0),(False,51.0)),((True,816.0),(True,51.0 ) ) ] 
 Sum & Mean of all plus doubles : [ ( (  ) ) ] 



Sums: [(False,1734.0),(True,816.0)]
Sums': [(False,1734.0),(True,816.0)]
Means: [(False,51.0),(True,51.0)]
Sums & Means: ([(False,1734.0),(True,816.0)],[(False,51.0),(True,51.0)])
Sum & Mean of each: [((False,1734.0),(False,51.0)),((True,816.0),(True,51.0))]
Sum & Mean of all plus doubles: [((False,10101.0),(False,75.38059701492539)),((True,5049.0),(True,76.5))]

-}
