{-# OPTIONS_GHC -Wno-orphans #-}

-- |
-- Module      : Streamly.Internal.Data.Stream.Common
-- Copyright   : (c) 2017 Composewell Technologies
-- License     : BSD-3-Clause
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
-- Portability : GHC
--
-- Low level functions using StreamK as the intermediate stream type. These
-- functions are used in other stream modules to implement their instances.
--
module Streamly.Internal.Data.Stream.Common
    (
    -- * Conversion operations
      fromList
    , toList

    -- * Fold operations
    , foldr
    , foldl'
    , fold

    -- * Zip style operations
    , eqBy
    , cmpBy
    )
where

#include "inline.hs"

import Streamly.Internal.Data.Fold.Type (Fold (..))

import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
import qualified Streamly.Internal.Data.Stream.StreamD.Type as D

import Prelude hiding (foldr, repeat)

------------------------------------------------------------------------------
-- Conversions
------------------------------------------------------------------------------

-- |
-- @
-- fromList = 'Prelude.foldr' 'K.cons' 'K.nil'
-- @
--
-- Construct a stream from a list of pure values. This is more efficient than
-- 'K.fromFoldable' for serial streams.
--
{-# INLINE_EARLY fromList #-}
fromList :: Monad m => [a] -> K.StreamK m a
fromList :: [a] -> StreamK m a
fromList = Stream m a -> StreamK m a
forall (m :: * -> *) a. Monad m => Stream m a -> StreamK m a
D.toStreamK (Stream m a -> StreamK m a)
-> ([a] -> Stream m a) -> [a] -> StreamK m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> Stream m a
forall (m :: * -> *) a. Applicative m => [a] -> Stream m a
D.fromList
{-# RULES "fromList fallback to StreamK" [1]
    forall a. D.toStreamK (D.fromList a) = K.fromFoldable a #-}

-- | Convert a stream into a list in the underlying monad.
--
{-# INLINE toList #-}
toList :: Monad m => K.StreamK m a -> m [a]
toList :: StreamK m a -> m [a]
toList StreamK m a
m = Stream m a -> m [a]
forall (m :: * -> *) a. Monad m => Stream m a -> m [a]
D.toList (Stream m a -> m [a]) -> Stream m a -> m [a]
forall a b. (a -> b) -> a -> b
$ StreamK m a -> Stream m a
forall (m :: * -> *) a. Applicative m => StreamK m a -> Stream m a
D.fromStreamK StreamK m a
m

------------------------------------------------------------------------------
-- Folds
------------------------------------------------------------------------------

{-# INLINE foldrM #-}
foldrM :: Monad m => (a -> m b -> m b) -> m b -> K.StreamK m a -> m b
foldrM :: (a -> m b -> m b) -> m b -> StreamK m a -> m b
foldrM a -> m b -> m b
step m b
acc StreamK m a
m = (a -> m b -> m b) -> m b -> Stream m a -> m b
forall (m :: * -> *) a b.
Monad m =>
(a -> m b -> m b) -> m b -> Stream m a -> m b
D.foldrM a -> m b -> m b
step m b
acc (Stream m a -> m b) -> Stream m a -> m b
forall a b. (a -> b) -> a -> b
$ StreamK m a -> Stream m a
forall (m :: * -> *) a. Applicative m => StreamK m a -> Stream m a
D.fromStreamK StreamK m a
m

{-# INLINE foldr #-}
foldr :: Monad m => (a -> b -> b) -> b -> K.StreamK m a -> m b
foldr :: (a -> b -> b) -> b -> StreamK m a -> m b
foldr a -> b -> b
f b
z = (a -> m b -> m b) -> m b -> StreamK m a -> m b
forall (m :: * -> *) a b.
Monad m =>
(a -> m b -> m b) -> m b -> StreamK m a -> m b
foldrM (\a
a m b
b -> a -> b -> b
f a
a (b -> b) -> m b -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m b
b) (b -> m b
forall (m :: * -> *) a. Monad m => a -> m a
return b
z)

-- | Strict left associative fold.
--
{-# INLINE foldl' #-}
foldl' ::
    Monad m => (b -> a -> b) -> b -> K.StreamK m a -> m b
foldl' :: (b -> a -> b) -> b -> StreamK m a -> m b
foldl' b -> a -> b
step b
begin StreamK m a
m = (b -> a -> b) -> b -> Stream m a -> m b
forall (m :: * -> *) b a.
Monad m =>
(b -> a -> b) -> b -> Stream m a -> m b
D.foldl' b -> a -> b
step b
begin (Stream m a -> m b) -> Stream m a -> m b
forall a b. (a -> b) -> a -> b
$ StreamK m a -> Stream m a
forall (m :: * -> *) a. Applicative m => StreamK m a -> Stream m a
D.fromStreamK StreamK m a
m


{-# INLINE fold #-}
fold :: Monad m => Fold m a b -> K.StreamK m a -> m b
fold :: Fold m a b -> StreamK m a -> m b
fold Fold m a b
fld StreamK m a
m = Fold m a b -> Stream m a -> m b
forall (m :: * -> *) a b.
Monad m =>
Fold m a b -> Stream m a -> m b
D.fold Fold m a b
fld (Stream m a -> m b) -> Stream m a -> m b
forall a b. (a -> b) -> a -> b
$ StreamK m a -> Stream m a
forall (m :: * -> *) a. Applicative m => StreamK m a -> Stream m a
D.fromStreamK StreamK m a
m

------------------------------------------------------------------------------
-- Comparison
------------------------------------------------------------------------------

-- | Compare two streams for equality
--
{-# INLINE eqBy #-}
eqBy :: Monad m =>
    (a -> b -> Bool) -> K.StreamK m a -> K.StreamK m b -> m Bool
eqBy :: (a -> b -> Bool) -> StreamK m a -> StreamK m b -> m Bool
eqBy a -> b -> Bool
f StreamK m a
m1 StreamK m b
m2 = (a -> b -> Bool) -> Stream m a -> Stream m b -> m Bool
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> Bool) -> Stream m a -> Stream m b -> m Bool
D.eqBy a -> b -> Bool
f (StreamK m a -> Stream m a
forall (m :: * -> *) a. Applicative m => StreamK m a -> Stream m a
D.fromStreamK StreamK m a
m1) (StreamK m b -> Stream m b
forall (m :: * -> *) a. Applicative m => StreamK m a -> Stream m a
D.fromStreamK StreamK m b
m2)

-- | Compare two streams
--
{-# INLINE cmpBy #-}
cmpBy
    :: Monad m
    => (a -> b -> Ordering) -> K.StreamK m a -> K.StreamK m b -> m Ordering
cmpBy :: (a -> b -> Ordering) -> StreamK m a -> StreamK m b -> m Ordering
cmpBy a -> b -> Ordering
f StreamK m a
m1 StreamK m b
m2 = (a -> b -> Ordering) -> Stream m a -> Stream m b -> m Ordering
forall (m :: * -> *) a b.
Monad m =>
(a -> b -> Ordering) -> Stream m a -> Stream m b -> m Ordering
D.cmpBy a -> b -> Ordering
f (StreamK m a -> Stream m a
forall (m :: * -> *) a. Applicative m => StreamK m a -> Stream m a
D.fromStreamK StreamK m a
m1) (StreamK m b -> Stream m b
forall (m :: * -> *) a. Applicative m => StreamK m a -> Stream m a
D.fromStreamK StreamK m b
m2)