{-# LANGUAGE BangPatterns #-}
module TermFold ( sumTillNegative
, sumTillNegative'
, sumTillNegative''
, sumTillNegative'''
) where
sumTillNegative :: [Int] -> Int
sumTillNegative :: [Int] -> Int
sumTillNegative = [Int] -> Int
forall a. Num a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum ([Int] -> Int) -> ([Int] -> [Int]) -> [Int] -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Bool) -> [Int] -> [Int]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0)
sumTillNegative' :: [Int] -> Int
sumTillNegative' :: [Int] -> Int
sumTillNegative' = Int -> [Int] -> Int
forall {t}. (Ord t, Num t) => t -> [t] -> t
go Int
0
where
go :: t -> [t] -> t
go !t
total [t]
rest =
case [t]
rest of
[] -> t
total
t
x:[t]
xs
| t
x t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< t
0 -> t
total
| Bool
otherwise -> t -> [t] -> t
go (t
total t -> t -> t
forall a. Num a => a -> a -> a
+ t
x) [t]
xs
sumTillNegative'' :: [Int] -> Int
sumTillNegative'' :: [Int] -> Int
sumTillNegative'' [Int]
xs = (Int -> (Int -> Int) -> Int -> Int)
-> (Int -> Int) -> [Int] -> Int -> Int
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Int -> (Int -> Int) -> Int -> Int
forall {t}. (Ord t, Num t) => t -> (t -> t) -> t -> t
step Int -> Int
forall a. a -> a
id [Int]
xs Int
0
where
step :: t -> (t -> t) -> t -> t
step t
x t -> t
cont t
acc
| t
x t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< t
0 = t
acc
| Bool
otherwise = t -> t
cont (t
acc t -> t -> t
forall a. Num a => a -> a -> a
+ t
x)
sumTillNegative''' :: [Int] -> Int
sumTillNegative''' :: [Int] -> Int
sumTillNegative''' = (Int -> Int -> Either Int Int) -> Int -> [Int] -> Int
forall b a. (b -> a -> Either b b) -> b -> [a] -> b
_foldTerminate Int -> Int -> Either Int Int
forall {b}. (Ord b, Num b) => b -> b -> Either b b
go Int
0
where
go :: b -> b -> Either b b
go !b
total b
x
| b
x b -> b -> Bool
forall a. Ord a => a -> a -> Bool
< b
0 = b -> Either b b
forall a b. a -> Either a b
Left b
total
| Bool
otherwise = b -> Either b b
forall a b. b -> Either a b
Right (b
total b -> b -> b
forall a. Num a => a -> a -> a
+ b
x)
_foldTerminate :: (b -> a -> Either b b) -> b -> [a] -> b
_foldTerminate :: forall b a. (b -> a -> Either b b) -> b -> [a] -> b
_foldTerminate b -> a -> Either b b
f b
accum0 [a]
list0 = (b -> b) -> (b -> b) -> Either b b -> b
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either b -> b
forall a. a -> a
id b -> b
forall a. a -> a
id (b -> [a] -> Either b b
forall {b}. b -> [a] -> Either b b
go b
accum0 [a]
list0)
where
go :: b -> [a] -> Either b b
go !b
accum [a]
rest = do
(a
x, [a]
xs) <- case [a]
rest of
[] -> b -> Either b (a, [a])
forall a b. a -> Either a b
Left b
accum
a
x:[a]
xs -> (a, [a]) -> Either b (a, [a])
forall a b. b -> Either a b
Right (a
x, [a]
xs)
b
accum' <- b -> a -> Either b b
f b
accum a
x
b -> [a] -> Either b b
go b
accum' [a]
xs