#### Center

M
A
```module Statistics.Center where

import qualified Data.Sort as S
import qualified Data.Vector.Generic as VG
import qualified Data.Vector.Algorithms.Intro as VGAI

-- Measures of central tendency.

arithmeticMean :: (Foldable t, Fractional a) => t a -> a
arithmeticMean vals = (sum vals) / (fromIntegral \$ length vals)

geometricMean :: (Foldable t, Floating a) => t a -> a
geometricMean vals = (product vals) ** (1/(fromIntegral \$ length vals))

harmonicMean :: (Foldable t, Functor t, Fractional a) => t a -> a
harmonicMean vals = (sum \$ fmap (1/) vals) / (fromIntegral \$ length vals)

-- For median, since the containers are sorted differently, we need to use
-- different methods

medianList :: (Fractional a, Ord a) => [a] -> a
medianList = medianListSorted . S.sort

medianVector
:: (VG.Vector vector a, Foldable vector, Fractional a, Ord a)
=> vector a -> a
medianVector = medianVectorSorted . VG.modify VGAI.sort

-- When sorted, the two median algorithms are quite similar. We can reduce
-- duplication by adding an export list to the module and using more
-- higher-order functions but let's leave this for a different PR.

medianListSorted :: Fractional a => [a] -> a
medianListSorted vals
| odd n = vals !! mid
| otherwise = arithmeticMean \$ take 2 \$ drop (mid - 1) vals
where
n = length vals
mid = n `div` 2

medianVectorSorted
:: (VG.Vector vector a, Foldable vector, Fractional a)
=> vector a -> a
medianVectorSorted vals
| odd n = vals VG.! mid
| otherwise = arithmeticMean \$ VG.take 2 \$ VG.drop (mid - 1) vals
where
n = length vals
mid = n `div` 2
```  