packages feed

streamly-core-0.1.0: src/Streamly/Internal/Data/Stream/Zip.hs

{-# LANGUAGE UndecidableInstances #-}

-- |
-- Module      : Streamly.Internal.Data.Stream.Zip
-- Copyright   : (c) 2017 Composewell Technologies
--
-- License     : BSD3
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
-- Portability : GHC
--
-- To run examples in this module:
--
-- >>> import qualified Streamly.Data.Fold as Fold
-- >>> import qualified Streamly.Data.Stream as Stream
-- >>> import qualified Streamly.Internal.Data.Stream.Zip as Stream
--
module Streamly.Internal.Data.Stream.Zip
    (
      ZipStream (..)
    , ZipSerialM
    , ZipSerial
    )
where

import Data.Functor.Identity (Identity(..))
import GHC.Exts (IsList(..), IsString(..))
import Streamly.Internal.Data.Stream.Type (Stream)
import Text.Read
       ( Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec
       , readListPrecDefault)

import qualified Streamly.Internal.Data.Stream.Bottom as Stream
import qualified Streamly.Internal.Data.Stream.Generate as Stream

-- $setup
-- >>> import qualified Streamly.Data.Fold as Fold
-- >>> import qualified Streamly.Data.Stream as Stream
-- >>> import qualified Streamly.Internal.Data.Stream.Zip as Stream

------------------------------------------------------------------------------
-- Serially Zipping Streams
------------------------------------------------------------------------------

-- | For 'ZipStream':
--
-- @
-- (<>) = 'Streamly.Data.Stream.append'
-- (\<*>) = 'Streamly.Data.Stream.zipWith' id
-- @
--
-- Applicative evaluates the streams being zipped serially:
--
-- >>> s1 = Stream.ZipStream $ Stream.fromFoldable [1, 2]
-- >>> s2 = Stream.ZipStream $ Stream.fromFoldable [3, 4]
-- >>> s3 = Stream.ZipStream $ Stream.fromFoldable [5, 6]
-- >>> s = (,,) <$> s1 <*> s2 <*> s3
-- >>> Stream.fold Fold.toList (Stream.unZipStream s)
-- [(1,3,5),(2,4,6)]
--
newtype ZipStream m a = ZipStream {unZipStream :: Stream m a}
        deriving (Functor, Semigroup, Monoid)

deriving instance IsList (ZipStream Identity a)
deriving instance (a ~ Char) => IsString (ZipStream Identity a)
deriving instance Eq a => Eq (ZipStream Identity a)
deriving instance Ord a => Ord (ZipStream Identity a)
deriving instance (Foldable m, Monad m) => Foldable (ZipStream m)
deriving instance Traversable (ZipStream Identity)

instance Show a => Show (ZipStream Identity a) where
    showsPrec p dl = showParen (p > 10) $
        showString "fromList " . shows (toList dl)

instance Read a => Read (ZipStream Identity a) where
    readPrec = parens $ prec 10 $ do
        Ident "fromList" <- lexP
        fromList <$> readPrec
    readListPrec = readListPrecDefault

type ZipSerialM = ZipStream

-- | An IO stream whose applicative instance zips streams serially.
--
type ZipSerial = ZipSerialM IO

instance Monad m => Applicative (ZipStream m) where
    pure = ZipStream . Stream.repeat

    {-# INLINE (<*>) #-}
    ZipStream m1 <*> ZipStream m2 = ZipStream $ Stream.zipWith id m1 m2