packages feed

streamly-core-0.3.0: src/Streamly/Internal/Data/StreamK/Transformer.hs

-- |
-- Module      : Streamly.Internal.Data.StreamK.Transformer
-- Copyright   : (c) 2017 Composewell Technologies
-- License     : BSD3
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
-- Portability : GHC
--
module Streamly.Internal.Data.StreamK.Transformer
    (
      foldlT
    , foldrT

    , liftInner
    , evalStateT

    , localReaderT
    )
where

import Control.Monad.Trans.Class (MonadTrans(lift))
import Control.Monad.Trans.State.Strict (StateT)
import Streamly.Internal.Data.StreamK.Type
    (StreamK(..), nil, cons, uncons, concatEffect, foldStream, mkStream)
import Control.Monad.Trans.Reader (ReaderT, local)

import qualified Control.Monad.Trans.State.Strict as State

-- | Lazy left fold to an arbitrary transformer monad.
{-# INLINE foldlT #-}
foldlT :: (Monad m, Monad (s m), MonadTrans s)
    => (s m b -> a -> s m b) -> s m b -> StreamK m a -> s m b
foldlT step = go
  where
    go acc m1 = do
        res <- lift $ uncons m1
        case res of
            Just (h, t) -> go (step acc h) t
            Nothing -> acc

-- | Right associative fold to an arbitrary transformer monad.
{-# INLINE foldrT #-}
foldrT :: (Monad m, Monad (s m), MonadTrans s)
    => (a -> s m b -> s m b) -> s m b -> StreamK m a -> s m b
foldrT step final = go
  where
    go m1 = do
        res <- lift $ uncons m1
        case res of
            Just (h, t) -> step h (go t)
            Nothing -> final

------------------------------------------------------------------------------
-- Lifting inner monad
------------------------------------------------------------------------------

{-# INLINE evalStateT #-}
evalStateT :: Monad m => m s -> StreamK (StateT s m) a -> StreamK m a
evalStateT = go

    where

    go st m1 = concatEffect $ fmap f (st >>= State.runStateT (uncons m1))

    f (res, s1) =
        case res of
            Just (h, t) -> cons h (go (return s1) t)
            Nothing -> nil

{-# INLINE liftInner #-}
liftInner :: (Monad m, MonadTrans t, Monad (t m)) =>
    StreamK m a -> StreamK (t m) a
liftInner = go

    where

    go m1 = concatEffect $ fmap f $ lift $ uncons m1

    f res =
        case res of
            Just (h, t) -> cons h (go t)
            Nothing -> nil

-- | Modify the environment of the underlying ReaderT monad.
{-# INLINABLE localReaderT #-}
localReaderT :: (r -> r) -> StreamK (ReaderT r m) a -> StreamK (ReaderT r m) a
localReaderT f m =
    mkStream $ \st yld sng stp ->
        let single = local f . sng
            yieldk a r = local f $ yld a (localReaderT f r)
        in foldStream st yieldk single (local f stp) m