@@ -13,6 +13,8 @@
1313-- To run examples in this module:
1414--
1515-- >>> import qualified Streamly.Prelude as Stream
16+-- >>> import qualified Streamly.Internal.Data.Stream as D
17+-- >>> import qualified Streamly.Data.Fold as Fold
1618--
1719module Streamly.Internal.Data.Stream.Zip
1820 {-# DEPRECATED "Use \"Streamly.Data.Stream.MkType\" instead." #-}
@@ -23,6 +25,8 @@ module Streamly.Internal.Data.Stream.Zip
2325 , zipWithK
2426 , zipWithMK
2527
28+ , ZipConcurrent (..)
29+
2630 -- * Deprecated
2731 , ZipStream
2832 )
@@ -50,6 +54,7 @@ import Streamly.Internal.BaseCompat ((#.))
5054import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
5155import Streamly.Internal.Data.Stream.Serial (SerialT(..))
5256import Streamly.Internal.Data.StreamK (Stream)
57+import Streamly.Internal.Data.Stream.Concurrent (MonadAsync, parZipWith)
5358
5459import qualified Streamly.Internal.Data.Stream.Common as P
5560import qualified Streamly.Internal.Data.StreamK as K
@@ -62,6 +67,8 @@ import Prelude hiding (map, repeat, zipWith)
6267
6368-- $setup
6469-- >>> import qualified Streamly.Prelude as Stream
70+-- >>> import qualified Streamly.Internal.Data.Stream as D
71+-- >>> import qualified Streamly.Data.Fold as Fold
6572-- >>> import Control.Concurrent (threadDelay)
6673-- >>> :{
6774-- delay n = do
@@ -136,3 +143,27 @@ instance Monad m => Applicative (ZipSerialM m) where
136143
137144FOLDABLE_INSTANCE(ZipSerialM)
138145TRAVERSABLE_INSTANCE(ZipSerialM)
146+
147+-------------------------------------------------------------------------------
148+-- ZipConcurrent
149+-------------------------------------------------------------------------------
150+
151+newtype ZipConcurrent m a = ZipConcurrent {getZipConcurrent :: D.Stream m a}
152+ deriving (Functor)
153+
154+-- | An IO stream whose applicative instance zips streams concurrently. Note
155+-- that it uses the default concurrency options.
156+--
157+-- >>> s = ZipConcurrent $ D.fromList [1, 2, 3]
158+-- >>> x = (,,) <$> s <*> s <*> s
159+-- >>> D.fold Fold.toList (getZipConcurrent x)
160+-- [(1,1,1),(2,2,2),(3,3,3)]
161+--
162+-- @since 0.9.0
163+
164+instance MonadAsync m => Applicative (ZipConcurrent m) where
165+ pure = ZipConcurrent . D.repeat
166+
167+ {-# INLINE (<*>) #-}
168+ ZipConcurrent m1 <*> ZipConcurrent m2 =
169+ ZipConcurrent $ parZipWith id id m1 m2