{-# LANGUAGE DeriveFoldable #-}

-- | Module    :  Data.FiniteSupportStream
-- Copyright   :  (C) 2025 Alexey Tochin
-- License     :  BSD3 (see the file LICENSE)
-- Maintainer  :  Alexey Tochin <Alexey.Tochin@gmail.com>
--
-- This module provides functionality for working with infinite streams that have
-- finite support (i.e., only finitely many non-zero elements). The streams are
-- internally represented as arrays for efficient computation.
--
-- Any linear functional on an ordinary stream ('Data.Stream.Stream')
-- can be represented as a finite support stream.
-- Inversely, any finite support stream can be represented as
-- a linear functional on an ordinary stream.
module Data.FiniteSupportStream
  ( -- * The type of finite support streams
    FiniteSupportStream (toVector, MkFiniteSupportStream),

    -- * Basic functions
    supportLength,
    null,
    head,
    tail,
    cons,
    cons',
    streamsConvolution,
    finiteSupportStreamSum,
    unsafeMap,

    -- * Transformations
    optimize,
    unsafeZip,
    unsafeZipWith,

    -- * Construction
    mkFiniteSupportStream',
    empty,
    singleton,
    singleton',
    replicate,
    replicate',
    unsafeFromList,
    fromTuple,
    finiteSupportStreamBasis,

    -- * Conversion
    multiplicativeAction,
    takeArray,
    takeList,
    toList,
    toInfiniteList,

    -- * Fold tools
    foldlWithStream,
    foldlWithStream',
  )
where

import Control.ExtendableMap (ExtandableMap, extendMap)
import Data.Eq ((==))
import Data.Foldable (Foldable, foldl')
import qualified Data.IndexedListLiterals as DILL
import Data.List (repeat, (++))
import qualified Data.List as DL
import Data.Maybe (fromMaybe)
import Data.Monoid (mconcat)
import qualified Data.Stream as DS
import Data.Tuple (fst)
import Data.Vector (Vector)
import qualified Data.Vector as DV
import Debug.SimpleExpr.Utils.Algebra
  ( AlgebraicPower ((^^)),
    Convolution ((|*|)),
    MultiplicativeAction ((*|)),
  )
import GHC.Base (Bool, Eq, fmap, id, ($), (.), (<>), (>))
import GHC.Natural (Natural)
import GHC.Real (fromIntegral)
import GHC.Show (Show, show)
import NumHask
  ( Additive,
    Distributive,
    Multiplicative,
    Subtractive,
    negate,
    zero,
    (*),
    (+),
    (-),
  )
import qualified NumHask
import Numeric.InfBackprop.Instances.NumHask ()
import Numeric.InfBackprop.Utils.Vector (safeHead, trimArrayTail)
import qualified Numeric.InfBackprop.Utils.Vector as DVIBP

-- | A stream with finite support, represented as a vector.
-- Elements beyond the vector's length are implicitly zero.
-- The vector may contain trailing zeros, which can be removed using 'optimize'.
--
-- The type parameter @a@ typically has an 'Additive' instance with a zero element.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int, Float, Bool(False, True))
-- >>> import Data.Vector (fromList)
--
-- >>> MkFiniteSupportStream $ fromList [0, 1, 2, 3] :: FiniteSupportStream Int
-- [0,1,2,3,0,0,0,...
--
-- >>> MkFiniteSupportStream $ fromList [0, 1, 2, 3] :: FiniteSupportStream Float
-- [0.0,1.0,2.0,3.0,0.0,0.0,0.0,...
--
-- >>> MkFiniteSupportStream $ fromList [False, True] :: FiniteSupportStream Bool
-- [False,True,False,False,False,...
newtype FiniteSupportStream a = MkFiniteSupportStream {forall a. FiniteSupportStream a -> Vector a
toVector :: DV.Vector a}
  deriving ((forall m. Monoid m => FiniteSupportStream m -> m)
-> (forall m a. Monoid m => (a -> m) -> FiniteSupportStream a -> m)
-> (forall m a. Monoid m => (a -> m) -> FiniteSupportStream a -> m)
-> (forall a b. (a -> b -> b) -> b -> FiniteSupportStream a -> b)
-> (forall a b. (a -> b -> b) -> b -> FiniteSupportStream a -> b)
-> (forall b a. (b -> a -> b) -> b -> FiniteSupportStream a -> b)
-> (forall b a. (b -> a -> b) -> b -> FiniteSupportStream a -> b)
-> (forall a. (a -> a -> a) -> FiniteSupportStream a -> a)
-> (forall a. (a -> a -> a) -> FiniteSupportStream a -> a)
-> (forall a. FiniteSupportStream a -> [a])
-> (forall a. FiniteSupportStream a -> Bool)
-> (forall a. FiniteSupportStream a -> Int)
-> (forall a. Eq a => a -> FiniteSupportStream a -> Bool)
-> (forall a. Ord a => FiniteSupportStream a -> a)
-> (forall a. Ord a => FiniteSupportStream a -> a)
-> (forall a. Num a => FiniteSupportStream a -> a)
-> (forall a. Num a => FiniteSupportStream a -> a)
-> Foldable FiniteSupportStream
forall a. Eq a => a -> FiniteSupportStream a -> Bool
forall a. Num a => FiniteSupportStream a -> a
forall a. Ord a => FiniteSupportStream a -> a
forall m. Monoid m => FiniteSupportStream m -> m
forall a. FiniteSupportStream a -> Bool
forall a. FiniteSupportStream a -> Int
forall a. FiniteSupportStream a -> [a]
forall a. (a -> a -> a) -> FiniteSupportStream a -> a
forall m a. Monoid m => (a -> m) -> FiniteSupportStream a -> m
forall b a. (b -> a -> b) -> b -> FiniteSupportStream a -> b
forall a b. (a -> b -> b) -> b -> FiniteSupportStream a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall m. Monoid m => FiniteSupportStream m -> m
fold :: forall m. Monoid m => FiniteSupportStream m -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> FiniteSupportStream a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> FiniteSupportStream a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> FiniteSupportStream a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> FiniteSupportStream a -> m
$cfoldr :: forall a b. (a -> b -> b) -> b -> FiniteSupportStream a -> b
foldr :: forall a b. (a -> b -> b) -> b -> FiniteSupportStream a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> FiniteSupportStream a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> FiniteSupportStream a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> FiniteSupportStream a -> b
foldl :: forall b a. (b -> a -> b) -> b -> FiniteSupportStream a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> FiniteSupportStream a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> FiniteSupportStream a -> b
$cfoldr1 :: forall a. (a -> a -> a) -> FiniteSupportStream a -> a
foldr1 :: forall a. (a -> a -> a) -> FiniteSupportStream a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> FiniteSupportStream a -> a
foldl1 :: forall a. (a -> a -> a) -> FiniteSupportStream a -> a
$ctoList :: forall a. FiniteSupportStream a -> [a]
toList :: forall a. FiniteSupportStream a -> [a]
$cnull :: forall a. FiniteSupportStream a -> Bool
null :: forall a. FiniteSupportStream a -> Bool
$clength :: forall a. FiniteSupportStream a -> Int
length :: forall a. FiniteSupportStream a -> Int
$celem :: forall a. Eq a => a -> FiniteSupportStream a -> Bool
elem :: forall a. Eq a => a -> FiniteSupportStream a -> Bool
$cmaximum :: forall a. Ord a => FiniteSupportStream a -> a
maximum :: forall a. Ord a => FiniteSupportStream a -> a
$cminimum :: forall a. Ord a => FiniteSupportStream a -> a
minimum :: forall a. Ord a => FiniteSupportStream a -> a
$csum :: forall a. Num a => FiniteSupportStream a -> a
sum :: forall a. Num a => FiniteSupportStream a -> a
$cproduct :: forall a. Num a => FiniteSupportStream a -> a
product :: forall a. Num a => FiniteSupportStream a -> a
Foldable)

-- | Lifts a function to work with finite support streams.
-- This function applies the provided function to each element of the stream support.
-- The function is usafe because it is not checked that the argument function
-- maps zero to zero, which is expected.
--
-- ==== __Examples__
--
-- >>> unsafeMap (*2) (MkFiniteSupportStream $ DV.fromList [0, 1, 2, 3])
-- [0,2,4,6,0,0,0,...
--
-- >>> unsafeMap (+1) (MkFiniteSupportStream $ DV.fromList [0, 1, 2, 3])
-- [1,2,3,4,0,0,0,...
unsafeMap :: (a -> b) -> FiniteSupportStream a -> FiniteSupportStream b
unsafeMap :: forall a b.
(a -> b) -> FiniteSupportStream a -> FiniteSupportStream b
unsafeMap a -> b
f (MkFiniteSupportStream Vector a
array') = Vector b -> FiniteSupportStream b
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector b -> FiniteSupportStream b)
-> Vector b -> FiniteSupportStream b
forall a b. (a -> b) -> a -> b
$ (a -> b) -> Vector a -> Vector b
forall a b. (a -> b) -> Vector a -> Vector b
DV.map a -> b
f Vector a
array'

-- | `Eq` instance of `FiniteSupportStream`.
instance (Eq a, Additive a) => Eq (FiniteSupportStream a) where
  FiniteSupportStream a
x == :: FiniteSupportStream a -> FiniteSupportStream a -> Bool
== FiniteSupportStream a
y = Vector a
x' Vector a -> Vector a -> Bool
forall a. Eq a => a -> a -> Bool
== Vector a
y'
    where
      x' :: Vector a
x' = FiniteSupportStream a -> Vector a
forall a. FiniteSupportStream a -> Vector a
toVector (FiniteSupportStream a -> Vector a)
-> FiniteSupportStream a -> Vector a
forall a b. (a -> b) -> a -> b
$ FiniteSupportStream a -> FiniteSupportStream a
forall a.
(Eq a, Additive a) =>
FiniteSupportStream a -> FiniteSupportStream a
optimize FiniteSupportStream a
x
      y' :: Vector a
y' = FiniteSupportStream a -> Vector a
forall a. FiniteSupportStream a -> Vector a
toVector (FiniteSupportStream a -> Vector a)
-> FiniteSupportStream a -> Vector a
forall a b. (a -> b) -> a -> b
$ FiniteSupportStream a -> FiniteSupportStream a
forall a.
(Eq a, Additive a) =>
FiniteSupportStream a -> FiniteSupportStream a
optimize FiniteSupportStream a
y

-- | `Show` instance of `FiniteSupportStream`.
instance forall a. (Show a, Eq a, Additive a) => Show (FiniteSupportStream a) where
  show :: FiniteSupportStream a -> String
show FiniteSupportStream a
bs =
    let (MkFiniteSupportStream Vector a
array') = FiniteSupportStream a -> FiniteSupportStream a
forall a.
(Eq a, Additive a) =>
FiniteSupportStream a -> FiniteSupportStream a
optimize FiniteSupportStream a
bs
     in String
"["
          String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [String] -> String
forall a. Monoid a => [a] -> a
mconcat ((a -> String) -> [a] -> [String]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\a
x -> a -> String
forall a. Show a => a -> String
show a
x String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
",") (Vector a -> [a]
forall a. Vector a -> [a]
DV.toList Vector a
array' [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
forall a. Additive a => a
zero, a
forall a. Additive a => a
zero, a
forall a. Additive a => a
zero]))
          String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"..."

-- | `Additive` instance for `FiniteSupportStream`.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int)
--
-- >>> (unsafeFromList [1, 2, 3]) + (unsafeFromList [10, 20]) :: FiniteSupportStream Int
-- [11,22,3,0,0,0,...
--
-- >>> (unsafeFromList [1, 2, 3]) + empty
-- [1,2,3,0,0,0,...
instance (Additive a) => Additive (FiniteSupportStream a) where
  zero :: FiniteSupportStream a
zero = FiniteSupportStream a
forall a. FiniteSupportStream a
empty
  (MkFiniteSupportStream Vector a
a0) + :: FiniteSupportStream a
-> FiniteSupportStream a -> FiniteSupportStream a
+ (MkFiniteSupportStream Vector a
a1) =
    Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$
      (a -> a -> a)
-> (a -> a) -> (a -> a) -> Vector a -> Vector a -> Vector a
forall (v :: * -> *) a b c.
(Vector v a, Vector v b, Vector v c) =>
(a -> b -> c) -> (a -> c) -> (b -> c) -> v a -> v b -> v c
DVIBP.zipWith a -> a -> a
forall a. Additive a => a -> a -> a
(+) a -> a
forall a. a -> a
id a -> a
forall a. a -> a
id Vector a
a0 Vector a
a1

-- | `Subtractive` instance for `FiniteSupportStream`.
--
-- ==== __Examples__
--
-- >>> unsafeFromList [10, 20, 30] - unsafeFromList [1, 2]
-- [9,18,30,0,0,0,...
--
-- >>> unsafeFromList [1, 2, 3] - unsafeFromList [1, 2, 3]
-- [0,0,0,...
instance (Subtractive a) => Subtractive (FiniteSupportStream a) where
  negate :: FiniteSupportStream a -> FiniteSupportStream a
negate = (a -> a) -> FiniteSupportStream a -> FiniteSupportStream a
forall a b.
(a -> b) -> FiniteSupportStream a -> FiniteSupportStream b
unsafeMap a -> a
forall a. Subtractive a => a -> a
negate
  (MkFiniteSupportStream Vector a
a0) - :: FiniteSupportStream a
-> FiniteSupportStream a -> FiniteSupportStream a
- (MkFiniteSupportStream Vector a
a1) =
    Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$
      (a -> a -> a)
-> (a -> a) -> (a -> a) -> Vector a -> Vector a -> Vector a
forall (v :: * -> *) a b c.
(Vector v a, Vector v b, Vector v c) =>
(a -> b -> c) -> (a -> c) -> (b -> c) -> v a -> v b -> v c
DVIBP.zipWith (-) a -> a
forall a. a -> a
id a -> a
forall a. Subtractive a => a -> a
negate Vector a
a0 Vector a
a1

-- | `FiniteSupportStream` instance of `MultiplicativeAction`.
instance
  (MultiplicativeAction a b) =>
  MultiplicativeAction a (FiniteSupportStream b)
  where
  *| :: a -> FiniteSupportStream b -> FiniteSupportStream b
(*|) = (b -> b) -> FiniteSupportStream b -> FiniteSupportStream b
forall a b.
(a -> b) -> FiniteSupportStream a -> FiniteSupportStream b
unsafeMap ((b -> b) -> FiniteSupportStream b -> FiniteSupportStream b)
-> (a -> b -> b)
-> a
-> FiniteSupportStream b
-> FiniteSupportStream b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> b
forall a b. MultiplicativeAction a b => a -> b -> b
(*|)

-- | `FiniteSupportStream`instance of `AlgebraicPower` typeclass
-- for raising `FiniteSupportStream` to powers.
instance
  (AlgebraicPower b a) =>
  AlgebraicPower b (FiniteSupportStream a)
  where
  FiniteSupportStream a
x ^^ :: FiniteSupportStream a -> b -> FiniteSupportStream a
^^ b
n = (a -> a) -> FiniteSupportStream a -> FiniteSupportStream a
forall a b.
(a -> b) -> FiniteSupportStream a -> FiniteSupportStream b
unsafeMap (a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n) FiniteSupportStream a
x

-- | `FiniteSupportStream` instance of 'ExtandableMap' typeclass.
instance
  (ExtandableMap a b c d) =>
  ExtandableMap a b (FiniteSupportStream c) (FiniteSupportStream d)
  where
  extendMap :: (a -> b) -> FiniteSupportStream c -> FiniteSupportStream d
extendMap = (c -> d) -> FiniteSupportStream c -> FiniteSupportStream d
forall a b.
(a -> b) -> FiniteSupportStream a -> FiniteSupportStream b
unsafeMap ((c -> d) -> FiniteSupportStream c -> FiniteSupportStream d)
-> ((a -> b) -> c -> d)
-> (a -> b)
-> FiniteSupportStream c
-> FiniteSupportStream d
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> c -> d
forall a b c d. ExtandableMap a b c d => (a -> b) -> c -> d
extendMap

-- | `Convolution` instance for `FiniteSupportStream` and `Data.Stream.Stream`.
instance
  (Convolution a b c, Additive c) =>
  Convolution (FiniteSupportStream a) (DS.Stream b) c
  where
  FiniteSupportStream a
fss |*| :: FiniteSupportStream a -> Stream b -> c
|*| Stream b
s = (c -> a -> b -> c) -> c -> FiniteSupportStream a -> Stream b -> c
forall (t :: * -> *) b a c.
Foldable t =>
(b -> a -> c -> b) -> b -> t a -> Stream c -> b
foldlWithStream' (\c
acc a
x b
y -> c
acc c -> c -> c
forall a. Additive a => a -> a -> a
+ a
x a -> b -> c
forall a b c. Convolution a b c => a -> b -> c
|*| b
y) c
forall a. Additive a => a
zero FiniteSupportStream a
fss Stream b
s

-- | `Convolution` instance for `Data.Stream.Stream` and `FiniteSupportStream`.
instance
  (Convolution a b c, Additive c) =>
  Convolution (DS.Stream a) (FiniteSupportStream b) c
  where
  Stream a
s |*| :: Stream a -> FiniteSupportStream b -> c
|*| FiniteSupportStream b
fss = (c -> b -> a -> c) -> c -> FiniteSupportStream b -> Stream a -> c
forall (t :: * -> *) b a c.
Foldable t =>
(b -> a -> c -> b) -> b -> t a -> Stream c -> b
foldlWithStream' (\c
acc b
x a
y -> c
acc c -> c -> c
forall a. Additive a => a -> a -> a
+ a
y a -> b -> c
forall a b c. Convolution a b c => a -> b -> c
|*| b
x) c
forall a. Additive a => a
zero FiniteSupportStream b
fss Stream a
s

-- | `Convolution` instance for `FiniteSupportStream` and `FiniteSupportStream`.
instance
  (Convolution a b c, Additive c) =>
  Convolution (FiniteSupportStream a) (FiniteSupportStream b) c
  where
  (MkFiniteSupportStream Vector a
vx) |*| :: FiniteSupportStream a -> FiniteSupportStream b -> c
|*| (MkFiniteSupportStream Vector b
vy) = Vector a
vx Vector a -> Vector b -> c
forall a b c. Convolution a b c => a -> b -> c
|*| Vector b
vy

-- | Creates a finite support stream from a array, removing trailing zeros in the tail.
-- This is a constructor that ensures the minimal representation.
--
-- ==== __Examples__
--
-- >>> import Data.Vector (fromList)
--
-- >>> toVector $ mkFiniteSupportStream' $ fromList [0, 1, 2, 3, 0]
-- [0,1,2,3]
mkFiniteSupportStream' :: (Eq a, Additive a) => DV.Vector a -> FiniteSupportStream a
mkFiniteSupportStream' :: forall a. (Eq a, Additive a) => Vector a -> FiniteSupportStream a
mkFiniteSupportStream' Vector a
array' = Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$ a -> Vector a -> Vector a
forall (v :: * -> *) a. (Vector v a, Eq a) => a -> v a -> v a
trimArrayTail a
forall a. Additive a => a
zero Vector a
array'

-- | Removes trailing elements of the finite support stream's inner array
-- if they are zeros.
-- The resulting stream is represented in its minimal form.
--
-- ==== __Examples__
--
-- >>> optimize $ unsafeFromList [0, 1, 0, 3, 0, 0]
-- [0,1,0,3,0,0,0,...
optimize :: (Eq a, Additive a) => FiniteSupportStream a -> FiniteSupportStream a
optimize :: forall a.
(Eq a, Additive a) =>
FiniteSupportStream a -> FiniteSupportStream a
optimize (MkFiniteSupportStream Vector a
array') = Vector a -> FiniteSupportStream a
forall a. (Eq a, Additive a) => Vector a -> FiniteSupportStream a
mkFiniteSupportStream' Vector a
array'

-- | Returns the length of the stream's support (the vector length after optimization).
-- Trailing zeros are not counted in the support length.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int)
--
-- >>> supportLength $ unsafeFromList [0, 1, 2, 3]
-- 4
--
-- >>> supportLength $ unsafeFromList [0, 1, 2, 3, 0, 0]
-- 6
supportLength :: FiniteSupportStream a -> Natural
supportLength :: forall a. FiniteSupportStream a -> Natural
supportLength = Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Natural)
-> (FiniteSupportStream a -> Int)
-> FiniteSupportStream a
-> Natural
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Vector a -> Int
forall a. Vector a -> Int
DV.length (Vector a -> Int)
-> (FiniteSupportStream a -> Vector a)
-> FiniteSupportStream a
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FiniteSupportStream a -> Vector a
forall a. FiniteSupportStream a -> Vector a
toVector

-- | Checks if the finite support stream is empty.
--
-- ==== __Examples__
--
-- >>> null $ unsafeFromList [0, 1, 2]
-- False
--
-- >>> null $ unsafeFromList []
-- True
--
-- >>> null $ unsafeFromList [0, 0, 0]
-- False
null :: FiniteSupportStream a -> Bool
null :: forall a. FiniteSupportStream a -> Bool
null = Vector a -> Bool
forall a. Vector a -> Bool
DV.null (Vector a -> Bool)
-> (FiniteSupportStream a -> Vector a)
-> FiniteSupportStream a
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FiniteSupportStream a -> Vector a
forall a. FiniteSupportStream a -> Vector a
toVector

-- | Converts a finite list to a 'FiniteSupportStream'.
-- The list is assumed to be finite.
-- Trailing zero elements are not checked, and the inner array is not trimmed.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int, Float, Bool(False, True))
--
-- >>> unsafeFromList [0, 1, 2, 3] :: FiniteSupportStream Int
-- [0,1,2,3,0,0,0,...
--
-- >>> unsafeFromList [0, 1, 2, 3] :: FiniteSupportStream Float
-- [0.0,1.0,2.0,3.0,0.0,0.0,0.0,...
--
-- >>> unsafeFromList [False, True]
-- [False,True,False,False,False,...
unsafeFromList :: [a] -> FiniteSupportStream a
unsafeFromList :: forall a. [a] -> FiniteSupportStream a
unsafeFromList = Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> ([a] -> Vector a) -> [a] -> FiniteSupportStream a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Vector a
forall a. [a] -> Vector a
DV.fromList

-- | Converts a tuple into a `FiniteSupportStream`.
-- Trailing zero elements are not checked, and the inner array is not trimmed.
--
-- === __Examples__
--
-- >>> import GHC.Base (Int, Float, Bool(False, True))
-- >>> import GHC.Integer (Integer)
--
-- >>> fromTuple (0, 1, 2, 3) :: FiniteSupportStream Integer
-- [0,1,2,3,0,0,0,...
--
-- >>> fromTuple (0 :: Float, 1 :: Float, 2 :: Float, 3 :: Float) :: FiniteSupportStream Float
-- [0.0,1.0,2.0,3.0,0.0,0.0,0.0,...
--
-- >>> fromTuple (False, True) :: FiniteSupportStream Bool
-- [False,True,False,False,False,...
fromTuple ::
  (DILL.IndexedListLiterals input length a) =>
  input ->
  FiniteSupportStream a
fromTuple :: forall input (length :: Natural) a.
IndexedListLiterals input length a =>
input -> FiniteSupportStream a
fromTuple = Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> (input -> Vector a) -> input -> FiniteSupportStream a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Vector a
forall a. [a] -> Vector a
DV.fromList ([a] -> Vector a) -> (input -> [a]) -> input -> Vector a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. input -> [a]
forall input (length :: Natural) output.
IndexedListLiterals input length output =>
input -> [output]
DILL.toList

-- | Converts a finite support stream to a finite list.
-- The resulting list includes all elements of the stream, including any trailing zeros.
--
-- ==== __Examples__
--
-- >>> toList $ unsafeFromList [1, 2, 3]
-- [1,2,3]
--
-- >>> toList $ unsafeFromList [1, 2, 3, 0]
-- [1,2,3,0]
toList :: FiniteSupportStream a -> [a]
toList :: forall a. FiniteSupportStream a -> [a]
toList = Vector a -> [a]
forall a. Vector a -> [a]
DV.toList (Vector a -> [a])
-> (FiniteSupportStream a -> Vector a)
-> FiniteSupportStream a
-> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FiniteSupportStream a -> Vector a
forall a. FiniteSupportStream a -> Vector a
toVector

-- | Converts a finite support stream to an infinite list.
-- The resulting list contains all elements of the stream, followed by an infinite sequence of zeros.
--
-- ==== __Examples__
--
-- >>> import Data.List (take)
--
-- >>> take 5 $ toInfiniteList $ unsafeFromList [1, 2, 3]
-- [1,2,3,0,0]
toInfiniteList :: (Additive a) => FiniteSupportStream a -> [a]
toInfiniteList :: forall a. Additive a => FiniteSupportStream a -> [a]
toInfiniteList FiniteSupportStream a
fss = FiniteSupportStream a -> [a]
forall a. FiniteSupportStream a -> [a]
toList FiniteSupportStream a
fss [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ a -> [a]
forall a. a -> [a]
repeat a
forall a. Additive a => a
zero

-- | Empty finite support stream.
-- The stream contains only zeros.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int, Bool)
--
-- >>> empty :: FiniteSupportStream Int
-- [0,0,0,...
--
-- >>> empty :: FiniteSupportStream Bool
-- [False,False,False,...
empty :: FiniteSupportStream a
empty :: forall a. FiniteSupportStream a
empty = Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream Vector a
forall a. Vector a
DV.empty

-- | Returns the first element of the finite support stream.
-- If the stream is empty, it returns 'zero'.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int, Bool)
--
-- >>> head $ unsafeFromList [1, 2, 3]
-- 1
--
-- >>> head $ empty :: Int
-- 0
--
-- >>> head $ empty :: Bool
-- False
head :: (Additive a) => FiniteSupportStream a -> a
head :: forall a. Additive a => FiniteSupportStream a -> a
head (MkFiniteSupportStream Vector a
array') = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
forall a. Additive a => a
zero (Vector a -> Maybe a
forall (v :: * -> *) a (m :: * -> *).
(Vector v a, MonadPlus m) =>
v a -> m a
safeHead Vector a
array')

-- | Removes the first element of the finite support stream.
-- If the stream is empty, it returns an empty stream.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int)
--
-- >>> tail $ unsafeFromList [1, 2, 3]
-- [2,3,0,0,0,...
--
-- >>> tail $ empty :: FiniteSupportStream Int
-- [0,0,0,...
tail :: FiniteSupportStream a -> FiniteSupportStream a
tail :: forall a. FiniteSupportStream a -> FiniteSupportStream a
tail (MkFiniteSupportStream Vector a
array') =
  if Vector a -> Bool
forall a. Vector a -> Bool
DV.null Vector a
array'
    then FiniteSupportStream a
forall a. FiniteSupportStream a
empty
    else Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$ Vector a -> Vector a
forall a. Vector a -> Vector a
DV.tail Vector a
array'

-- | Takes the first @n@ elements of the finite support stream in the form of an array.
-- If @n@ is greater than the length of the stream, the result is padded with zeros.
-- The resulting array is not trimmed.
--
-- ==== __Examples__
--
-- >>> takeArray 5 $ unsafeFromList [1, 2, 3]
-- [1,2,3,0,0]
takeArray :: (Additive a) => Natural -> FiniteSupportStream a -> Vector a
takeArray :: forall a.
Additive a =>
Natural -> FiniteSupportStream a -> Vector a
takeArray Natural
n (MkFiniteSupportStream Vector a
array) =
  if Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Vector a -> Int
forall a. Vector a -> Int
DV.length Vector a
array
    then Vector a
array Vector a -> Vector a -> Vector a
forall a. Semigroup a => a -> a -> a
<> Int -> a -> Vector a
forall a. Int -> a -> Vector a
DV.replicate (Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
n Int -> Int -> Int
forall a. Subtractive a => a -> a -> a
- Vector a -> Int
forall a. Vector a -> Int
DV.length Vector a
array) a
forall a. Additive a => a
zero
    else Int -> Int -> Vector a -> Vector a
forall a. Int -> Int -> Vector a -> Vector a
DV.slice Int
0 (Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
n) Vector a
array

-- | Takes the first @n@ elements of the finite support stream in the form of a list.
-- If @n@ is greater than the length of the stream, the result is padded with zeros.
--
-- ==== __Examples__
--
-- >>> takeList 5 $ unsafeFromList [1, 2, 3]
-- [1,2,3,0,0]
takeList :: (Additive a) => Natural -> FiniteSupportStream a -> [a]
takeList :: forall a. Additive a => Natural -> FiniteSupportStream a -> [a]
takeList Natural
n FiniteSupportStream a
fss = Vector a -> [a]
forall a. Vector a -> [a]
DV.toList (Vector a -> [a]) -> Vector a -> [a]
forall a b. (a -> b) -> a -> b
$ Natural -> FiniteSupportStream a -> Vector a
forall a.
Additive a =>
Natural -> FiniteSupportStream a -> Vector a
takeArray Natural
n FiniteSupportStream a
fss

-- | Creates a finite support stream with exactly one element.
-- The element is not checked for being zero.
--
-- ==== __Examples__
--
-- >>> toVector $ singleton 42
-- [42]
--
-- >>> toVector $ singleton 0
-- [0]
--
-- >>> singleton 42
-- [42,0,0,0,...
--
-- >>> singleton 0
-- [0,0,0,...
--
-- >>> toVector $ singleton "a"
-- ["a"]
singleton :: a -> FiniteSupportStream a
singleton :: forall a. a -> FiniteSupportStream a
singleton = Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> (a -> Vector a) -> a -> FiniteSupportStream a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Vector a
forall a. a -> Vector a
DV.singleton

-- | Creates a finite support stream with exactly one non-zero element
-- if the provided element is not zero.
-- Returns the empty stream otherwise.
--
-- ==== __Examples__
--
-- >>> toVector $ singleton' 42
-- [42]
--
-- >>> toVector $ singleton' 0
-- []
--
-- >>> singleton' 42
-- [42,0,0,0,...
--
-- >>> singleton' 0
-- [0,0,0,...
singleton' :: (Additive a, Eq a) => a -> FiniteSupportStream a
singleton' :: forall a. (Additive a, Eq a) => a -> FiniteSupportStream a
singleton' a
x =
  if a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
forall a. Additive a => a
zero
    then FiniteSupportStream a
forall a. FiniteSupportStream a
empty
    else Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$ a -> Vector a
forall a. a -> Vector a
DV.singleton a
x

-- | Creates a finite support stream with a constant value along the support.
-- It does not check whether the provided value is zero.
-- In this case, the inner array contains only zeros.
--
-- ==== __Examples__
--
-- >>> replicate 3 42
-- [42,42,42,0,0,0,...
--
-- >>> replicate 2 0
-- [0,0,0,...
--
-- >>> toVector $ replicate 2 0
-- [0,0]
replicate :: Natural -> a -> FiniteSupportStream a
replicate :: forall a. Natural -> a -> FiniteSupportStream a
replicate Natural
n a
x = Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$ Int -> a -> Vector a
forall a. Int -> a -> Vector a
DV.replicate (Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
n) a
x

-- | Creates a finite support stream with a constant value along the support.
-- It checks whether the provided value is zero.
-- In this case, the inner array is empty.
--
-- ==== __Examples__
--
-- >>> replicate' 3 42
-- [42,42,42,0,0,0,...
--
-- >>> replicate' 2 0
-- [0,0,0,...
--
-- >>> toVector $ replicate' 2 0
-- []
replicate' :: (Additive a, Eq a) => Natural -> a -> FiniteSupportStream a
replicate' :: forall a.
(Additive a, Eq a) =>
Natural -> a -> FiniteSupportStream a
replicate' Natural
n a
x =
  if a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
forall a. Additive a => a
zero
    then FiniteSupportStream a
forall a. FiniteSupportStream a
empty
    else Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$ Int -> a -> Vector a
forall a. Int -> a -> Vector a
DV.replicate (Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
n) a
x

-- | Adds an element to the front of the finite support stream.
-- The inner array size is increased by exactly one.
-- The head element of the array is not checked for zero elements.
--
-- ==== __Examples__
--
-- >>> cons 42 (unsafeFromList [1, 2, 3])
-- [42,1,2,3,0,0,0,...
--
-- >>> toVector $ cons 0 empty
-- [0]
cons :: a -> FiniteSupportStream a -> FiniteSupportStream a
cons :: forall a. a -> FiniteSupportStream a -> FiniteSupportStream a
cons a
x = Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> (FiniteSupportStream a -> Vector a)
-> FiniteSupportStream a
-> FiniteSupportStream a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Vector a -> Vector a
forall a. a -> Vector a -> Vector a
DV.cons a
x (Vector a -> Vector a)
-> (FiniteSupportStream a -> Vector a)
-> FiniteSupportStream a
-> Vector a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FiniteSupportStream a -> Vector a
forall a. FiniteSupportStream a -> Vector a
toVector

-- | Adds an element to the front of the finite support stream.
-- The inner array size is increased by exactly one if the head element is not zero.
-- Otherwise, if the finite support stream is empty, the output is also the empty stream.
--
-- ==== __Examples__
--
-- >>> cons' 42 (unsafeFromList [1, 2, 3])
-- [42,1,2,3,0,0,0,...
--
-- >>> toVector $ cons' 0 empty
-- []
cons' :: (Additive a, Eq a) => a -> FiniteSupportStream a -> FiniteSupportStream a
cons' :: forall a.
(Additive a, Eq a) =>
a -> FiniteSupportStream a -> FiniteSupportStream a
cons' a
x FiniteSupportStream a
fss =
  let (MkFiniteSupportStream Vector a
array') = FiniteSupportStream a -> FiniteSupportStream a
forall a.
(Eq a, Additive a) =>
FiniteSupportStream a -> FiniteSupportStream a
optimize FiniteSupportStream a
fss
   in if Vector a -> Bool
forall a. Vector a -> Bool
DV.null Vector a
array'
        then a -> FiniteSupportStream a
forall a. (Additive a, Eq a) => a -> FiniteSupportStream a
singleton' a
x
        else Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$ a -> Vector a -> Vector a
forall a. a -> Vector a -> Vector a
DV.cons a
x Vector a
array'

-- | Creates a finite support stream basis vector.
-- The values of the zero and unit elements are provided as arguments.
--
-- ==== __Examples__
--
-- >>> finiteSupportStreamBasis 0 1 3
-- [0,0,0,1,0,0,0,...
finiteSupportStreamBasis :: a -> a -> Natural -> FiniteSupportStream a
finiteSupportStreamBasis :: forall a. a -> a -> Natural -> FiniteSupportStream a
finiteSupportStreamBasis a
zero' a
one' Natural
n =
  Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$ Vector a -> a -> Vector a
forall a. Vector a -> a -> Vector a
DV.snoc (Int -> a -> Vector a
forall a. Int -> a -> Vector a
DV.replicate (Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
n) a
zero') a
one'

-- | Convolves a stream with a finite support stream, producing a single value.
-- The result is the sum of element-wise products.
--
-- This operation is equivalent to applying the stream as a linear functional
-- to the finite support stream.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Float, Int)
-- >>> import GHC.Real ((/))
-- >>> import Data.Stream (iterate, take, Stream)
-- >>> import Data.HashMap.Internal.Array (fromList')
--
-- >>> s1 = iterate (+1) 0 :: Stream Int
-- >>> Data.Stream.take 5 s1
-- [0,1,2,3,4]
-- >>> fss1 = unsafeFromList [0, 0, 1] :: FiniteSupportStream Int
-- >>> streamsConvolution s1 fss1
-- 2
--
-- >>> s2 = iterate (/2) (1 :: Float) :: Stream Float
-- >>> Data.Stream.take 5 s2
-- [1.0,0.5,0.25,0.125,6.25e-2]
-- >>> fss2 = unsafeFromList $ Data.List.replicate 10 1 :: FiniteSupportStream Float
-- >>> streamsConvolution s2 fss2
-- 1.9980469
streamsConvolution ::
  (Distributive a) =>
  DS.Stream a ->
  FiniteSupportStream a ->
  a
streamsConvolution :: forall a. Distributive a => Stream a -> FiniteSupportStream a -> a
streamsConvolution Stream a
stream FiniteSupportStream a
fss =
  (a -> a -> a) -> a -> [a] -> a
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' a -> a -> a
forall a. Additive a => a -> a -> a
(+) a
forall a. Additive a => a
zero ((a -> a -> a) -> [a] -> [a] -> [a]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
DL.zipWith a -> a -> a
forall a. Multiplicative a => a -> a -> a
(*) (Stream a -> [a]
forall a. Stream a -> [a]
DS.toList Stream a
stream) (FiniteSupportStream a -> [a]
forall a. FiniteSupportStream a -> [a]
toList FiniteSupportStream a
fss))

-- | Applies the multiplicative action of the stream on the finite support stream.
-- The resulting stream's support length is less than or equal to
-- the stream's support length in the argument.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int)
--
-- >>> multiplicativeAction (DS.fromList [0 ..]) (unsafeFromList [1, 1, 0, 1])
-- [0,1,0,3,0,0,0,...
multiplicativeAction ::
  (Multiplicative a) =>
  DS.Stream a ->
  FiniteSupportStream a ->
  FiniteSupportStream a
multiplicativeAction :: forall a.
Multiplicative a =>
Stream a -> FiniteSupportStream a -> FiniteSupportStream a
multiplicativeAction Stream a
stream (MkFiniteSupportStream Vector a
array) =
  Vector a -> FiniteSupportStream a
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector a -> FiniteSupportStream a)
-> Vector a -> FiniteSupportStream a
forall a b. (a -> b) -> a -> b
$
    [a] -> Vector a
forall a. [a] -> Vector a
DV.fromList ([a] -> Vector a) -> [a] -> Vector a
forall a b. (a -> b) -> a -> b
$
      (a -> a -> a) -> [a] -> [a] -> [a]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
DL.zipWith a -> a -> a
forall a. Multiplicative a => a -> a -> a
(*) (Stream a -> [a]
forall a. Stream a -> [a]
DS.toList Stream a
stream) (Vector a -> [a]
forall a. Vector a -> [a]
DV.toList Vector a
array)

-- | Computes the sum of all elements the finite support stream.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int)
--
-- >>> finiteSupportStreamSum $ unsafeFromList [1, 2, 3, 0] :: Int
-- 6
--
-- >>> finiteSupportStreamSum empty :: Int
-- 0
finiteSupportStreamSum :: (Additive a) => FiniteSupportStream a -> a
finiteSupportStreamSum :: forall a. Additive a => FiniteSupportStream a -> a
finiteSupportStreamSum (MkFiniteSupportStream Vector a
array') = Vector a -> a
forall a (f :: * -> *). (Additive a, Foldable f) => f a -> a
NumHask.sum Vector a
array'

-- | Applies an element-wise binary operation to two streams.
--
-- Parameters:
--   * @f@ - Binary operation for overlapping elements
--   * @g@ - Unary operation for excess elements in first stream
--   * @h@ - Unary operation for excess elements in second stream
--
-- The resulting stream's length is the maximum of the input lengths,
-- with trailing elements transformed by @g@ or @h@ as appropriate.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int)
--
-- >>> let xs = unsafeFromList [10, 20, 30]
-- >>> let ys = unsafeFromList [1,2]
-- >>> unsafeZipWith (-) id negate xs ys
-- [9,18,30,0,0,0,...
unsafeZipWith ::
  -- | Binary operation for overlapping elements
  (a -> b -> c) ->
  -- | Operation for excess elements in first stream
  (a -> c) ->
  -- | Operation for excess elements in second stream
  (b -> c) ->
  FiniteSupportStream a ->
  FiniteSupportStream b ->
  FiniteSupportStream c
unsafeZipWith :: forall a b c.
(a -> b -> c)
-> (a -> c)
-> (b -> c)
-> FiniteSupportStream a
-> FiniteSupportStream b
-> FiniteSupportStream c
unsafeZipWith a -> b -> c
f a -> c
g b -> c
h (MkFiniteSupportStream Vector a
a0) (MkFiniteSupportStream Vector b
a1) =
  Vector c -> FiniteSupportStream c
forall a. Vector a -> FiniteSupportStream a
MkFiniteSupportStream (Vector c -> FiniteSupportStream c)
-> Vector c -> FiniteSupportStream c
forall a b. (a -> b) -> a -> b
$ (a -> b -> c)
-> (a -> c) -> (b -> c) -> Vector a -> Vector b -> Vector c
forall (v :: * -> *) a b c.
(Vector v a, Vector v b, Vector v c) =>
(a -> b -> c) -> (a -> c) -> (b -> c) -> v a -> v b -> v c
DVIBP.zipWith a -> b -> c
f a -> c
g b -> c
h Vector a
a0 Vector b
a1

-- | Lazy left fold over a foldable type @t@ and a `Data.Stream.Stream`.
--
-- ==== __Examples__
--
-- >>> foldlWithStream (\acc x y -> acc + x * y) 0 (unsafeFromList [1,1,1]) (DS.iterate (+1) 0)
-- 3
foldlWithStream ::
  (Foldable t) =>
  (b -> a -> c -> b) ->
  b ->
  t a ->
  DS.Stream c ->
  b
foldlWithStream :: forall (t :: * -> *) b a c.
Foldable t =>
(b -> a -> c -> b) -> b -> t a -> Stream c -> b
foldlWithStream b -> a -> c -> b
f b
acc0 t a
ta Stream c
stream0 =
  (b, Stream c) -> b
forall a b. (a, b) -> a
fst ((b, Stream c) -> b) -> (b, Stream c) -> b
forall a b. (a -> b) -> a -> b
$ ((b, Stream c) -> a -> (b, Stream c))
-> (b, Stream c) -> t a -> (b, Stream c)
forall b a. (b -> a -> b) -> b -> t a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (b, Stream c) -> a -> (b, Stream c)
step (b
acc0, Stream c
stream0) t a
ta
  where
    step :: (b, Stream c) -> a -> (b, Stream c)
step (b
acc, DS.Cons c
c Stream c
stream') a
a =
      (b -> a -> c -> b
f b
acc a
a c
c, Stream c
stream')

-- | Strinct left fold over a foldable type @t@ and a `Data.Stream.Stream`.
--
-- ==== __Examples__
--
-- >>> foldlWithStream (\acc x y -> acc + x * y) 0 (unsafeFromList [1,1,1]) (DS.iterate (+1) 0)
-- 3
foldlWithStream' ::
  (Foldable t) =>
  (b -> a -> c -> b) ->
  b ->
  t a ->
  DS.Stream c ->
  b
foldlWithStream' :: forall (t :: * -> *) b a c.
Foldable t =>
(b -> a -> c -> b) -> b -> t a -> Stream c -> b
foldlWithStream' b -> a -> c -> b
f !b
acc0 t a
ta Stream c
stream0 = (b, Stream c) -> b
forall a b. (a, b) -> a
fst ((b, Stream c) -> b) -> (b, Stream c) -> b
forall a b. (a -> b) -> a -> b
$ ((b, Stream c) -> a -> (b, Stream c))
-> (b, Stream c) -> t a -> (b, Stream c)
forall b a. (b -> a -> b) -> b -> t a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' (b, Stream c) -> a -> (b, Stream c)
step (b
acc0, Stream c
stream0) t a
ta
  where
    step :: (b, Stream c) -> a -> (b, Stream c)
step (!b
acc, DS.Cons !c
c Stream c
stream) a
a = let !acc' :: b
acc' = b -> a -> c -> b
f b
acc a
a c
c in (b
acc', Stream c
stream)

-- | Zips two finite support streams.
--
-- ==== __Examples__
--
-- >>> import GHC.Base (Int)
--
-- >>> unsafeZip (unsafeFromList [1, 2, 3]) (unsafeFromList [4, 5]) :: FiniteSupportStream (Int, Int)
-- [(1,4),(2,5),(3,0),(0,0),(0,0),(0,0),...
unsafeZip ::
  (Additive a, Additive b) =>
  FiniteSupportStream a ->
  FiniteSupportStream b ->
  FiniteSupportStream (a, b)
-- {-# ANN module "HLint: ignore Use zip" #-}
unsafeZip :: forall a b.
(Additive a, Additive b) =>
FiniteSupportStream a
-> FiniteSupportStream b -> FiniteSupportStream (a, b)
unsafeZip = (a -> b -> (a, b))
-> (a -> (a, b))
-> (b -> (a, b))
-> FiniteSupportStream a
-> FiniteSupportStream b
-> FiniteSupportStream (a, b)
forall a b c.
(a -> b -> c)
-> (a -> c)
-> (b -> c)
-> FiniteSupportStream a
-> FiniteSupportStream b
-> FiniteSupportStream c
unsafeZipWith (,) (,b
forall a. Additive a => a
zero) (a
forall a. Additive a => a
zero,)