module ListLive (
    cons,
    append,
    splitAt,
    span,
    afterEach,
    dropWhileRev,

    sumInteger,
    productInteger,
    iterateInteger,
    iterateIntegerList,
    applyStrictList,
    applyStrictListList,
    ) where

import Tuple
import Function
import Bool
import Prelude ( (-), (+), (*), Int, Integer, Integral, Bool, foldr, null, reverse )


cons :: a -> [a] -> [a] ;
cons :: forall a. a -> [a] -> [a]
cons a
x [a]
xs = a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
xs ;

append :: [a] -> [a] -> [a] ;
append :: forall a. [a] -> [a] -> [a]
append = ([a] -> [a] -> [a]) -> [a] -> [a] -> [a]
forall b a c. (b -> a -> c) -> a -> b -> c
flip ( (a -> [a] -> [a]) -> [a] -> [a] -> [a]
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr a -> [a] -> [a]
forall a. a -> [a] -> [a]
cons ) ;


{-
This is not very efficient
since the result of the recursive call to 'splitAt' cannot be shared.
-}
splitAt :: Int -> [a] -> Tuple.Pair [a] [a] ;
splitAt :: forall a. Int -> [a] -> Pair [a] [a]
splitAt Int
0 [a]
xs = [a] -> [a] -> Pair [a] [a]
forall a b. a -> b -> Pair a b
Pair [] [a]
xs ;
splitAt Int
_ [] = [a] -> [a] -> Pair [a] [a]
forall a b. a -> b -> Pair a b
Pair [] [] ;
splitAt Int
n (a
x : [a]
xs) = a -> Pair [a] [a] -> Pair [a] [a]
forall a. a -> Pair [a] [a] -> Pair [a] [a]
consFirst a
x ( Int -> [a] -> Pair [a] [a]
forall a. Int -> [a] -> Pair [a] [a]
splitAt (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) [a]
xs ) ;

span :: (a -> Bool) -> [a] -> Tuple.Pair [a] [a] ;
span :: forall a. (a -> Bool) -> [a] -> Pair [a] [a]
span a -> Bool
_ [] = [a] -> [a] -> Pair [a] [a]
forall a b. a -> b -> Pair a b
Pair [] [] ;
span a -> Bool
p (a
x : [a]
xs) =
   Bool -> Pair [a] [a] -> Pair [a] [a] -> Pair [a] [a]
forall a. Bool -> a -> a -> a
ifThenElse (a -> Bool
p a
x) ( a -> Pair [a] [a] -> Pair [a] [a]
forall a. a -> Pair [a] [a] -> Pair [a] [a]
consFirst a
x ( (a -> Bool) -> [a] -> Pair [a] [a]
forall a. (a -> Bool) -> [a] -> Pair [a] [a]
span a -> Bool
p [a]
xs ) ) ([a] -> [a] -> Pair [a] [a]
forall a b. a -> b -> Pair a b
Pair [] (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
xs)) ;

consFirst :: a -> Tuple.Pair [a] [a] -> Tuple.Pair [a] [a] ;
consFirst :: forall a. a -> Pair [a] [a] -> Pair [a] [a]
consFirst a
x Pair [a] [a]
p = [a] -> [a] -> Pair [a] [a]
forall a b. a -> b -> Pair a b
Pair (a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: Pair [a] [a] -> [a]
forall a b. Pair a b -> a
fst Pair [a] [a]
p) (Pair [a] [a] -> [a]
forall a b. Pair a b -> b
snd Pair [a] [a]
p) ;


afterEach :: a -> [a] -> [a] ;
afterEach :: forall a. a -> [a] -> [a]
afterEach a
_y [] = [] ;
afterEach a
y (a
x : [a]
xs) = a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: a
y a -> [a] -> [a]
forall a. a -> [a] -> [a]
: a -> [a] -> [a]
forall a. a -> [a] -> [a]
afterEach a
y [a]
xs ;


dropWhileRev :: (a -> Bool) -> [a] -> [a] ;
dropWhileRev :: forall a. (a -> Bool) -> [a] -> [a]
dropWhileRev a -> Bool
p =
   (a -> [a] -> [a]) -> [a] -> [a] -> [a]
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ((a -> Bool) -> a -> [a] -> [a]
forall a. (a -> Bool) -> a -> [a] -> [a]
dropWhileRevElem a -> Bool
p) [] ;

dropWhileRevElem :: (a -> Bool) -> a -> [a] -> [a] ;
dropWhileRevElem :: forall a. (a -> Bool) -> a -> [a] -> [a]
dropWhileRevElem a -> Bool
p a
x [a]
xs = Bool -> [a] -> [a] -> [a]
forall a. Bool -> a -> a -> a
ifThenElse (a -> Bool
p a
x Bool -> Bool -> Bool
&& [a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [a]
xs) [] (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
xs) ;


-- * functions that are somehow strict

-- | constant space usage in contrast to 'sum'
sumInteger :: (Integral a) => [a] -> a ;
sumInteger :: forall a. Integral a => [a] -> a
sumInteger = a -> [a] -> a
forall a. Integral a => a -> [a] -> a
sumIntegerAux a
0 ;

sumIntegerAux :: (Integral a) => a -> [a] -> a ;
sumIntegerAux :: forall a. Integral a => a -> [a] -> a
sumIntegerAux a
0 [] = a
0 ;
sumIntegerAux a
s [] = a
s ;
sumIntegerAux a
s (a
x:[a]
xs) = a -> [a] -> a
forall a. Integral a => a -> [a] -> a
sumIntegerAux (a
sa -> a -> a
forall a. Num a => a -> a -> a
+a
x) [a]
xs ;


productInteger :: (Integral a) => [a] -> a ;
productInteger :: forall a. Integral a => [a] -> a
productInteger = a -> [a] -> a
forall a. Integral a => a -> [a] -> a
productIntegerAux a
1 ;

productIntegerAux :: (Integral a) => a -> [a] -> a ;
productIntegerAux :: forall a. Integral a => a -> [a] -> a
productIntegerAux a
0 [] = a
0 ;
productIntegerAux a
p [] = a
p ;
productIntegerAux a
p (a
x:[a]
xs) = a -> [a] -> a
forall a. Integral a => a -> [a] -> a
productIntegerAux (a
pa -> a -> a
forall a. Num a => a -> a -> a
*a
x) [a]
xs ;


-- | constant space usage in contrast to 'iterate'
iterateInteger, iterateIntegerAux ::
   (Integer -> Integer) -> Integer -> [Integer] ;
iterateInteger :: (Integer -> Integer) -> Integer -> [Integer]
iterateInteger Integer -> Integer
f = (Integer -> [Integer]) -> Integer -> [Integer]
forall a. (Integer -> a) -> Integer -> a
applyStrict ((Integer -> Integer) -> Integer -> [Integer]
iterateIntegerAux Integer -> Integer
f) ;
iterateIntegerAux :: (Integer -> Integer) -> Integer -> [Integer]
iterateIntegerAux Integer -> Integer
f Integer
x = Integer
x Integer -> [Integer] -> [Integer]
forall a. a -> [a] -> [a]
: (Integer -> Integer) -> Integer -> [Integer]
iterateInteger Integer -> Integer
f (Integer -> Integer
f Integer
x) ;

iterateIntegerList, iterateIntegerListAux ::
   ([Integer] -> [Integer]) -> [Integer] -> [[Integer]] ;
iterateIntegerList :: ([Integer] -> [Integer]) -> [Integer] -> [[Integer]]
iterateIntegerList [Integer] -> [Integer]
f = ([Integer] -> [[Integer]]) -> [Integer] -> [[Integer]]
forall a. ([Integer] -> a) -> [Integer] -> a
applyStrictList (([Integer] -> [Integer]) -> [Integer] -> [[Integer]]
iterateIntegerListAux [Integer] -> [Integer]
f) ;
iterateIntegerListAux :: ([Integer] -> [Integer]) -> [Integer] -> [[Integer]]
iterateIntegerListAux [Integer] -> [Integer]
f [Integer]
x = [Integer]
x [Integer] -> [[Integer]] -> [[Integer]]
forall a. a -> [a] -> [a]
: ([Integer] -> [Integer]) -> [Integer] -> [[Integer]]
iterateIntegerList [Integer] -> [Integer]
f ([Integer] -> [Integer]
f [Integer]
x) ;

{- even stricter: it always updates the accumulator, also if the updated value is not needed because the list is aborted earlier
iterateInteger, iterateIntegerAux0 ::
   (Integer -> Integer) -> Integer -> [Integer] ;
iterateIntegerAux1 ::
   (Integer -> Integer) -> Integer -> Integer -> [Integer] ;
iterateInteger f = applyStrict (iterateIntegerAux0 f) ;
iterateIntegerAux0 f x = applyStrict (iterateIntegerAux1 f x) (f x) ;
iterateIntegerAux1 f x fx = x : iterateInteger f fx ;
-}

{- too strict for DeBruijn
iterateIntegerList, iterateIntegerListAux0 ::
   ([Integer] -> [Integer]) -> [Integer] -> [[Integer]] ;
iterateIntegerListAux1 ::
   ([Integer] -> [Integer]) -> [Integer] -> [Integer] -> [[Integer]] ;
iterateIntegerList f = applyStrictList (iterateIntegerListAux0 f) ;
iterateIntegerListAux0 f x = applyStrictList (iterateIntegerListAux1 f x) (f x) ;
iterateIntegerListAux1 f x fx = x : iterateIntegerList f fx ;
-}



applyStrictList :: ([Integer] -> a) -> ([Integer] -> a) ;
applyStrictList :: forall a. ([Integer] -> a) -> [Integer] -> a
applyStrictList [Integer] -> a
f [Integer]
xs = ([Integer] -> a) -> [Integer] -> [Integer] -> a
forall a. ([Integer] -> a) -> [Integer] -> [Integer] -> a
applyStrictListAux [Integer] -> a
f [] ([Integer] -> [Integer]
forall a. [a] -> [a]
reverse [Integer]
xs) ;

applyStrictListAux :: ([Integer] -> a) -> [Integer] -> ([Integer] -> a) ;
applyStrictListAux :: forall a. ([Integer] -> a) -> [Integer] -> [Integer] -> a
applyStrictListAux [Integer] -> a
f [Integer]
ys [] = [Integer] -> a
f [Integer]
ys ;
applyStrictListAux [Integer] -> a
f [Integer]
ys (Integer
0:[Integer]
xs) = ([Integer] -> a) -> [Integer] -> [Integer] -> a
forall a. ([Integer] -> a) -> [Integer] -> [Integer] -> a
applyStrictListAux [Integer] -> a
f (Integer
0Integer -> [Integer] -> [Integer]
forall a. a -> [a] -> [a]
:[Integer]
ys) [Integer]
xs ;
applyStrictListAux [Integer] -> a
f [Integer]
ys (Integer
x:[Integer]
xs) = ([Integer] -> a) -> [Integer] -> [Integer] -> a
forall a. ([Integer] -> a) -> [Integer] -> [Integer] -> a
applyStrictListAux [Integer] -> a
f (Integer
xInteger -> [Integer] -> [Integer]
forall a. a -> [a] -> [a]
:[Integer]
ys) [Integer]
xs ;


applyStrictListList :: ([[Integer]] -> a) -> ([[Integer]] -> a) ;
applyStrictListList :: forall a. ([[Integer]] -> a) -> [[Integer]] -> a
applyStrictListList [[Integer]] -> a
f [[Integer]]
xs = ([[Integer]] -> a) -> [[Integer]] -> [[Integer]] -> a
forall a. ([[Integer]] -> a) -> [[Integer]] -> [[Integer]] -> a
applyStrictListListAux [[Integer]] -> a
f [] ([[Integer]] -> [[Integer]]
forall a. [a] -> [a]
reverse [[Integer]]
xs) ;

applyStrictListListAux :: ([[Integer]] -> a) -> [[Integer]] -> ([[Integer]] -> a) ;
applyStrictListListAux :: forall a. ([[Integer]] -> a) -> [[Integer]] -> [[Integer]] -> a
applyStrictListListAux [[Integer]] -> a
f [[Integer]]
ys [] = [[Integer]] -> a
f [[Integer]]
ys ;
applyStrictListListAux [[Integer]] -> a
f [[Integer]]
ys ([Integer]
x:[[Integer]]
xs) =
   ([Integer] -> [[Integer]] -> a) -> [Integer] -> [[Integer]] -> a
forall a. ([Integer] -> a) -> [Integer] -> a
applyStrictList (([[Integer]] -> a) -> [[Integer]] -> [[Integer]] -> a
forall a. ([[Integer]] -> a) -> [[Integer]] -> [[Integer]] -> a
applyStrictListListAux [[Integer]] -> a
f ([[Integer]] -> [[Integer]] -> a)
-> ([Integer] -> [[Integer]]) -> [Integer] -> [[Integer]] -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Integer] -> [[Integer]] -> [[Integer]])
-> [[Integer]] -> [Integer] -> [[Integer]]
forall b a c. (b -> a -> c) -> a -> b -> c
flip [Integer] -> [[Integer]] -> [[Integer]]
forall a. a -> [a] -> [a]
cons [[Integer]]
ys) [Integer]
x [[Integer]]
xs ;