```{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE ExplicitForAll, TypeOperators #-}

module Data.Array.Repa.Operators.Reduction
( fold, foldAll
, sum,  sumAll)
where
import Data.Array.Repa.Index
import Data.Array.Repa.Internals.Elt
import Data.Array.Repa.Internals.Base
import Data.Array.Repa.Shape		as S
import qualified Data.Vector.Unboxed	as V
import Prelude				hiding (sum)

-- | Sequentially fold the innermost dimension of an array.
--	Combine this with `transpose` to fold any other dimension.
fold 	:: (Shape sh, Elt a)
=> (a -> a -> a)
-> a
-> Array (sh :. Int) a
-> Array sh a

{-# INLINE fold #-}
fold f x arr
= x `seq` arr `deepSeqArray`
let	sh' :. n	= extent arr
elemFn i 	= V.foldl' f x
\$ V.map	(\ix -> arr ! (i :. ix))
(V.enumFromTo 0 (n - 1))
in	fromFunction sh' elemFn

-- | Sequentially fold all the elements of an array.
foldAll :: (Shape sh, Elt a)
=> (a -> a -> a)
-> a
-> Array sh a
-> a

{-# INLINE foldAll #-}
foldAll f x arr
= V.foldl' f x
\$ V.map ((arr !) . (S.fromIndex (extent arr)))
\$ V.enumFromTo
0
((S.size \$ extent arr) - 1)

-- | Sum the innermost dimension of an array.
sum	:: (Shape sh, Elt a, Num a)
=> Array (sh :. Int) a
-> Array sh a

{-# INLINE sum #-}
sum arr	= fold (+) 0 arr

-- | Sum all the elements of an array.
sumAll	:: (Shape sh, Elt a, Num a)
=> Array sh a
-> a

{-# INLINE sumAll #-}
sumAll arr
= V.foldl' (+) 0
\$ V.map ((arr !) . (S.fromIndex (extent arr)))
\$ V.enumFromTo
0
((S.size \$ extent arr) - 1)

```