2{-# LANGUAGE ConstraintKinds #-}
3{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE FlexibleInstances #-}
5{-# LANGUAGE GeneralizedNewtypeDeriving#-}
6{-# LANGUAGE InstanceSigs #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE TypeFamilies #-}
9{-# LANGUAGE UndecidableInstances #-} -- XXX
12-- Module : Streamly.Internal.Data.Stream.Zip
13-- Copyright : (c) 2017 Harendra Kumar
16-- Maintainer : streamly@composewell.com
17-- Stability : experimental
21module Streamly.Internal.Data.Stream.Zip
43import Control.Applicative (liftA2)
44import Control.DeepSeq (NFData(..))
45#if MIN_VERSION_deepseq(1,4,3)
46import Control.DeepSeq (NFData1(..))
48import Data.Functor.Identity (Identity, runIdentity)
49import Data.Foldable (fold)
50#if __GLASGOW_HASKELL__ < 808
51import Data.Semigroup (Semigroup(..))
53import GHC.Exts (IsList(..), IsString(..))
54import Text.Read (Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec,
56import Prelude hiding (map, repeat, zipWith)
58import Streamly.Internal.Data.Stream.StreamK (IsStream(..), Stream)
59import Streamly.Internal.Data.SVar (MonadAsync, adaptState)
61import qualified Streamly.Internal.Data.Stream.Prelude as P
62import qualified Streamly.Internal.Data.Stream.StreamK as K
63import qualified Streamly.Internal.Data.Stream.StreamD as D
65#ifdef USE_STREAMK_ONLY
66import qualified Streamly.Internal.Data.Stream.StreamK as S
68import qualified Streamly.Internal.Data.Stream.StreamD as S
71#include "Instances.hs"
73-- | Like 'zipWith' but using a monadic zipping function.
76{-# INLINABLE zipWithM #-}
77zipWithM :: (IsStream t, Monad m) => (a -> b -> m c) -> t m a -> t m b -> t m c
78zipWithM f m1 m2 = P.fromStreamS $ S.zipWithM f (P.toStreamS m1) (P.toStreamS m2)
80-- | Zip two streams serially using a pure zipping function.
83-- > S.toList $ S.zipWith (+) (S.fromList [1,2,3]) (S.fromList [4,5,6])
88{-# INLINABLE zipWith #-}
89zipWith :: (IsStream t, Monad m) => (a -> b -> c) -> t m a -> t m b -> t m c
90zipWith f m1 m2 = P.fromStreamS $ S.zipWith f (P.toStreamS m1) (P.toStreamS m2)
92------------------------------------------------------------------------------
94------------------------------------------------------------------------------
96-- The CPS version and the direct version of zipAsyncWithM below seem to have
97-- identical performance. However, we need to use the StreamD version of
98-- mkParallel which uses a direct implementation of fromSVar. In comparison to
99-- CPS version of fromSVar the direct version gives a 2x improvement.
101-- | Like 'zipWithM' but zips concurrently i.e. both the streams being zipped
102-- are generated concurrently.
105{-# INLINE zipAsyncWithM #-}
106zipAsyncWithM :: (IsStream t, MonadAsync m)
107 => (a -> b -> m c) -> t m a -> t m b -> t m c
108zipAsyncWithM f m1 m2 = K.mkStream $ \st stp sng yld -> do
109 ma <- D.mkParallel (adaptState st) (D.toStreamD m1)
110 mb <- D.mkParallel (adaptState st) (D.toStreamD m2)
111 K.foldStream st stp sng yld $ zipWithM f (D.fromStreamD ma)
114zipAsyncWithM f m1 m2 =
115 fromStreamD $ D.zipAsyncWithM f (toStreamD m1) (toStreamD m2)
118-- | Like 'zipWith' but zips concurrently i.e. both the streams being zipped
119-- are generated concurrently.
122{-# INLINE zipAsyncWith #-}
123zipAsyncWith :: (IsStream t, MonadAsync m)
124 => (a -> b -> c) -> t m a -> t m b -> t m c
125zipAsyncWith f = zipAsyncWithM (\a b -> return (f a b))
127------------------------------------------------------------------------------
128-- Serially Zipping Streams
129------------------------------------------------------------------------------
131-- | The applicative instance of 'ZipSerialM' zips a number of streams serially
132-- i.e. it produces one element from each stream serially and then zips all
136-- main = (toList . 'zipSerially' $ (,,) \<$\> s1 \<*\> s2 \<*\> s3) >>= print
137-- where s1 = fromFoldable [1, 2]
138-- s2 = fromFoldable [3, 4]
139-- s3 = fromFoldable [5, 6]
145-- The 'Semigroup' instance of this type works the same way as that of
149newtype ZipSerialM m a = ZipSerialM {getZipSerialM :: Stream m a}
150 deriving (Semigroup, Monoid)
154{-# DEPRECATED ZipStream "Please use 'ZipSerialM' instead." #-}
155type ZipStream = ZipSerialM
157-- | An IO stream whose applicative instance zips streams serially.
160type ZipSerial = ZipSerialM IO
162-- | Fix the type of a polymorphic stream as 'ZipSerialM'.
165zipSerially :: IsStream t => ZipSerialM m a -> t m a
168-- | Same as 'zipSerially'.
171{-# DEPRECATED zipping "Please use zipSerially instead." #-}
172zipping :: IsStream t => ZipSerialM m a -> t m a
175consMZip :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
176consMZip m ms = fromStream $ K.consMStream m (toStream ms)
178instance IsStream ZipSerialM where
179 toStream = getZipSerialM
180 fromStream = ZipSerialM
183 {-# SPECIALIZE consM :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
184 consM :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
188 {-# SPECIALIZE (|:) :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
189 (|:) :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
192LIST_INSTANCES(ZipSerialM)
193NFDATA1_INSTANCE(ZipSerialM)
195instance Monad m => Functor (ZipSerialM m) where
197 fmap f (ZipSerialM m) = D.fromStreamD $ D.mapM (return . f) $ D.toStreamD m
199instance Monad m => Applicative (ZipSerialM m) where
200 pure = ZipSerialM . K.repeat
204FOLDABLE_INSTANCE(ZipSerialM)
205TRAVERSABLE_INSTANCE(ZipSerialM)
207------------------------------------------------------------------------------
208-- Parallely Zipping Streams
209------------------------------------------------------------------------------
211-- | Like 'ZipSerialM' but zips in parallel, it generates all the elements to
212-- be zipped concurrently.
215-- main = (toList . 'zipAsyncly' $ (,,) \<$\> s1 \<*\> s2 \<*\> s3) >>= print
216-- where s1 = fromFoldable [1, 2]
217-- s2 = fromFoldable [3, 4]
218-- s3 = fromFoldable [5, 6]
224-- The 'Semigroup' instance of this type works the same way as that of
228newtype ZipAsyncM m a = ZipAsyncM {getZipAsyncM :: Stream m a}
229 deriving (Semigroup, Monoid)
231-- | An IO stream whose applicative instance zips streams wAsyncly.
234type ZipAsync = ZipAsyncM IO
236-- | Fix the type of a polymorphic stream as 'ZipAsyncM'.
239zipAsyncly :: IsStream t => ZipAsyncM m a -> t m a
242-- | Same as 'zipAsyncly'.
245{-# DEPRECATED zippingAsync "Please use zipAsyncly instead." #-}
246zippingAsync :: IsStream t => ZipAsyncM m a -> t m a
247zippingAsync = zipAsyncly
249consMZipAsync :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
250consMZipAsync m ms = fromStream $ K.consMStream m (toStream ms)
252instance IsStream ZipAsyncM where
253 toStream = getZipAsyncM
254 fromStream = ZipAsyncM
257 {-# SPECIALIZE consM :: IO a -> ZipAsyncM IO a -> ZipAsyncM IO a #-}
258 consM :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
259 consM = consMZipAsync
262 {-# SPECIALIZE (|:) :: IO a -> ZipAsyncM IO a -> ZipAsyncM IO a #-}
263 (|:) :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
266instance Monad m => Functor (ZipAsyncM m) where
268 fmap f (ZipAsyncM m) = D.fromStreamD $ D.mapM (return . f) $ D.toStreamD m
270instance MonadAsync m => Applicative (ZipAsyncM m) where
271 pure = ZipAsyncM . K.repeat
273 m1 <*> m2 = zipAsyncWith id m1 m2
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list