{-# LANGUAGE RebindableSyntax #-}
{- |
Functions that are counterparts of the @generic@ functions in "Data.List"
using NumericPrelude.Numeric type classes.
For input arguments we use the restrictive @ToInteger@ constraint,
although in principle @RealRing@ would be enough.
However we think that @take 0.5 xs@ is rather a bug than a feature,
thus we forbid fractional types.
On the other hand fractional types as result can be quite handy,
e.g. in @average xs = sum xs / length xs@.
-}
module NumericPrelude.List.Generic
   ((!!), lengthLeft, lengthRight, replicate,
    take, drop, splitAt,
    findIndex, elemIndex, findIndices, elemIndices,
   ) where

import NumericPrelude.List.Checked ((!!), )

import qualified Algebra.ToInteger  as ToInteger
import qualified Algebra.Ring       as Ring
import Algebra.Ring (one, )
import Algebra.Additive (zero, (+), (-), )

import qualified Data.Maybe         as Maybe
import Data.Tuple.HT (mapFst, )

import NumericPrelude.Base as List
   hiding (take, drop, splitAt, length, replicate, (!!), )


replicate :: (ToInteger.C n) => n -> a -> [a]
replicate :: n -> a -> [a]
replicate n
n a
x = n -> [a] -> [a]
forall n a. C n => n -> [a] -> [a]
take n
n (a -> [a]
forall a. a -> [a]
List.repeat a
x)

take :: (ToInteger.C n) => n -> [a] -> [a]
take :: n -> [a] -> [a]
take n
_ [] = []
take n
n (a
x:[a]
xs) =
   if n
nn -> n -> Bool
forall a. Ord a => a -> a -> Bool
<=n
forall a. C a => a
zero
     then []
     else a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: n -> [a] -> [a]
forall n a. C n => n -> [a] -> [a]
take (n
nn -> n -> n
forall a. C a => a -> a -> a
-n
forall a. C a => a
one) [a]
xs

drop :: (ToInteger.C n) => n -> [a] -> [a]
drop :: n -> [a] -> [a]
drop n
_ [] = []
drop n
n xt :: [a]
xt@(a
_:[a]
xs) =
   if n
nn -> n -> Bool
forall a. Ord a => a -> a -> Bool
<=n
forall a. C a => a
zero
     then [a]
xt
     else n -> [a] -> [a]
forall n a. C n => n -> [a] -> [a]
drop (n
nn -> n -> n
forall a. C a => a -> a -> a
-n
forall a. C a => a
one) [a]
xs

splitAt :: (ToInteger.C n) => n -> [a] -> ([a], [a])
splitAt :: n -> [a] -> ([a], [a])
splitAt n
_ [] = ([], [])
splitAt n
n xt :: [a]
xt@(a
x:[a]
xs) =
   if n
nn -> n -> Bool
forall a. Ord a => a -> a -> Bool
<=n
forall a. C a => a
zero
     then ([], [a]
xt)
     else ([a] -> [a]) -> ([a], [a]) -> ([a], [a])
forall a c b. (a -> c) -> (a, b) -> (c, b)
mapFst (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:) (([a], [a]) -> ([a], [a])) -> ([a], [a]) -> ([a], [a])
forall a b. (a -> b) -> a -> b
$ n -> [a] -> ([a], [a])
forall n a. C n => n -> [a] -> ([a], [a])
splitAt (n
nn -> n -> n
forall a. C a => a -> a -> a
-n
forall a. C a => a
one) [a]
xs


{- |
Left associative length computation
that is appropriate for types like @Integer@.
-}
lengthLeft :: (Ring.C n) => [a] -> n
lengthLeft :: [a] -> n
lengthLeft = (n -> a -> n) -> n -> [a] -> n
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl (\n
n a
_ -> n
nn -> n -> n
forall a. C a => a -> a -> a
+n
forall a. C a => a
one) n
forall a. C a => a
zero

{- |
Right associative length computation
that is appropriate for types like @Peano@ number.
-}
lengthRight :: (Ring.C n) => [a] -> n
lengthRight :: [a] -> n
lengthRight = (a -> n -> n) -> n -> [a] -> n
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
List.foldr (\a
_ n
n -> n
forall a. C a => a
onen -> n -> n
forall a. C a => a -> a -> a
+n
n) n
forall a. C a => a
zero

elemIndex :: (Ring.C n, Eq a) => a -> [a] -> Maybe n
elemIndex :: a -> [a] -> Maybe n
elemIndex a
e = (a -> Bool) -> [a] -> Maybe n
forall n a. C n => (a -> Bool) -> [a] -> Maybe n
findIndex (a
ea -> a -> Bool
forall a. Eq a => a -> a -> Bool
==)

elemIndices :: (Ring.C n, Eq a) => a -> [a] -> [n]
elemIndices :: a -> [a] -> [n]
elemIndices a
e = (a -> Bool) -> [a] -> [n]
forall n a. C n => (a -> Bool) -> [a] -> [n]
findIndices (a
ea -> a -> Bool
forall a. Eq a => a -> a -> Bool
==)

findIndex :: Ring.C n => (a -> Bool) -> [a] -> Maybe n
findIndex :: (a -> Bool) -> [a] -> Maybe n
findIndex a -> Bool
p = [n] -> Maybe n
forall a. [a] -> Maybe a
Maybe.listToMaybe ([n] -> Maybe n) -> ([a] -> [n]) -> [a] -> Maybe n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Bool) -> [a] -> [n]
forall n a. C n => (a -> Bool) -> [a] -> [n]
findIndices a -> Bool
p

findIndices :: Ring.C n => (a -> Bool) -> [a] -> [n]
findIndices :: (a -> Bool) -> [a] -> [n]
findIndices a -> Bool
p =
   ((n, a) -> n) -> [(n, a)] -> [n]
forall a b. (a -> b) -> [a] -> [b]
map (n, a) -> n
forall a b. (a, b) -> a
fst ([(n, a)] -> [n]) -> ([a] -> [(n, a)]) -> [a] -> [n]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
   ((n, a) -> Bool) -> [(n, a)] -> [(n, a)]
forall a. (a -> Bool) -> [a] -> [a]
filter (a -> Bool
p (a -> Bool) -> ((n, a) -> a) -> (n, a) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (n, a) -> a
forall a b. (a, b) -> b
snd) ([(n, a)] -> [(n, a)]) -> ([a] -> [(n, a)]) -> [a] -> [(n, a)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
   [n] -> [a] -> [(n, a)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((n -> n) -> n -> [n]
forall a. (a -> a) -> a -> [a]
iterate (n
forall a. C a => a
onen -> n -> n
forall a. C a => a -> a -> a
+) n
forall a. C a => a
zero)