-- Time-stamp: <Fri Stardate: Stardate: [-27]1923.33 hwloidl>
--
-- Compile:   ghc -threaded -O2 -rtsopts -o foo_thr foo.hs 
-- Run:       ./foo_thr +RTS -N4 -s
-- For the source code of the strategies, look-up the parallel module on hackage:
-- https://hackage.haskell.org/package/parallel/
-----------------------------------------------------------------------------
		
module Main(main) where

-- import System.Environment -- needed if you want to use getArgs to read cmd-line args
import System.IO
-- these are needed for parallel code!
import Control.Parallel.Strategies
import Control.DeepSeq

-- | 'parListChunk' applies a strategy 's' in chunks of 'n' over a list
parListChunk :: Int -> Strategy [a] -> Strategy [a]
parListChunk n s = Main.parListSplitAt n s (Main.parListChunk n s)

-- helper for the above; note the use of strategy composition to make it parallel 
parListSplitAt :: Int -> Strategy [a] -> Strategy [a] -> Strategy [a]
parListSplitAt n stratPref stratSuff =
  Main.evalListSplitAt n (rpar `dot` stratPref) (rpar `dot` stratSuff)

-- | @'evaListSplitAt' n stratPref stratSuff@ evaluates the prefix
-- (of length @n@) of a list according to @stratPref@ and its the suffix
-- according to @stratSuff@.
evalListSplitAt :: Int -> Strategy [a] -> Strategy [a] -> Strategy [a]
evalListSplitAt _ _ _ [] = return []
evalListSplitAt n stratPref stratSuff xs
  = let (ys,zs) = splitAt n xs in
    stratPref ys >>= \ys' ->
    stratSuff zs >>= \zs' ->
    return (ys' ++ zs')

-- std rec def of factorial
-- Exercise: make it tail recursive and measure both time and heap performance of both versions
factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n - 1)

-- fairly minimal tester
-- use fully qualified names, such as Main.parListChunk, if you have several definitions in scope
main = do
         -- use the pre-defined strategies:
         -- print (map Main.factorial [12..30] `using` (Control.Parallel.Strategies.parListChunk 2 rdeepseq))
         -- use the our own strategies, defined in this module:
         print (map Main.factorial [12..30] `using` (Main.parListChunk 2 rdeepseq))
         -- Exercise: read in the input from the command line; try different values for chunking large lists
     
