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.Foldable (Foldable(foldl'), fold)
49import Data.Functor.Identity (Identity(..), runIdentity)
50import Data.Maybe (fromMaybe)
51import Data.Semigroup (Endo(..))
52#if __GLASGOW_HASKELL__ < 808
53import Data.Semigroup (Semigroup(..))
55import GHC.Exts (IsList(..), IsString(..))
56import Text.Read (Lexeme(Ident), lexP, parens, prec, readPrec, readListPrec,
58import Prelude hiding (map, repeat, zipWith, errorWithoutStackTrace)
60import Streamly.Internal.BaseCompat ((#.), errorWithoutStackTrace)
61import Streamly.Internal.Data.Stream.StreamK (IsStream(..), Stream)
62import Streamly.Internal.Data.Strict (Maybe'(..), toMaybe)
63import Streamly.Internal.Data.SVar (MonadAsync)
65import qualified Streamly.Internal.Data.Stream.Prelude as P
66import qualified Streamly.Internal.Data.Stream.StreamK as K
67import qualified Streamly.Internal.Data.Stream.StreamD as D
69#ifdef USE_STREAMK_ONLY
70import qualified Streamly.Internal.Data.Stream.StreamK as S
72import qualified Streamly.Internal.Data.Stream.StreamD as S
75#include "Instances.hs"
77-- | Like 'zipWith' but using a monadic zipping function.
80{-# INLINABLE zipWithM #-}
81zipWithM :: (IsStream t, Monad m) => (a -> b -> m c) -> t m a -> t m b -> t m c
82zipWithM f m1 m2 = P.fromStreamS $ S.zipWithM f (P.toStreamS m1) (P.toStreamS m2)
84-- | Zip two streams serially using a pure zipping function.
87-- > S.toList $ S.zipWith (+) (S.fromList [1,2,3]) (S.fromList [4,5,6])
92{-# INLINABLE zipWith #-}
93zipWith :: (IsStream t, Monad m) => (a -> b -> c) -> t m a -> t m b -> t m c
94zipWith f m1 m2 = P.fromStreamS $ S.zipWith f (P.toStreamS m1) (P.toStreamS m2)
96------------------------------------------------------------------------------
98------------------------------------------------------------------------------
100-- | Like 'zipWithM' but zips concurrently i.e. both the streams being zipped
101-- are generated concurrently.
104{-# INLINE zipAsyncWithM #-}
105zipAsyncWithM :: (IsStream t, MonadAsync m)
106 => (a -> b -> m c) -> t m a -> t m b -> t m c
107zipAsyncWithM f m1 m2 = D.fromStreamD $
108 D.zipWithM f (D.mkParallelD $ D.toStreamD m1)
109 (D.mkParallelD $ D.toStreamD m2)
111-- | Like 'zipWith' but zips concurrently i.e. both the streams being zipped
112-- are generated concurrently.
115{-# INLINE zipAsyncWith #-}
116zipAsyncWith :: (IsStream t, MonadAsync m)
117 => (a -> b -> c) -> t m a -> t m b -> t m c
118zipAsyncWith f = zipAsyncWithM (\a b -> return (f a b))
120------------------------------------------------------------------------------
121-- Serially Zipping Streams
122------------------------------------------------------------------------------
124-- | The applicative instance of 'ZipSerialM' zips a number of streams serially
125-- i.e. it produces one element from each stream serially and then zips all
129-- main = (toList . 'zipSerially' $ (,,) \<$\> s1 \<*\> s2 \<*\> s3) >>= print
130-- where s1 = fromFoldable [1, 2]
131-- s2 = fromFoldable [3, 4]
132-- s3 = fromFoldable [5, 6]
138-- The 'Semigroup' instance of this type works the same way as that of
142newtype ZipSerialM m a = ZipSerialM {getZipSerialM :: Stream m a}
143 deriving (Semigroup, Monoid)
147{-# DEPRECATED ZipStream "Please use 'ZipSerialM' instead." #-}
148type ZipStream = ZipSerialM
150-- | An IO stream whose applicative instance zips streams serially.
153type ZipSerial = ZipSerialM IO
155-- | Fix the type of a polymorphic stream as 'ZipSerialM'.
158zipSerially :: IsStream t => ZipSerialM m a -> t m a
161-- | Same as 'zipSerially'.
164{-# DEPRECATED zipping "Please use zipSerially instead." #-}
165zipping :: IsStream t => ZipSerialM m a -> t m a
168consMZip :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
169consMZip m ms = fromStream $ K.consMStream m (toStream ms)
171instance IsStream ZipSerialM where
172 toStream = getZipSerialM
173 fromStream = ZipSerialM
176 {-# SPECIALIZE consM :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
177 consM :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
181 {-# SPECIALIZE (|:) :: IO a -> ZipSerialM IO a -> ZipSerialM IO a #-}
182 (|:) :: Monad m => m a -> ZipSerialM m a -> ZipSerialM m a
185LIST_INSTANCES(ZipSerialM)
186NFDATA1_INSTANCE(ZipSerialM)
188instance Monad m => Functor (ZipSerialM m) where
190 fmap f (ZipSerialM m) = D.fromStreamD $ D.mapM (return . f) $ D.toStreamD m
192instance Monad m => Applicative (ZipSerialM m) where
193 pure = ZipSerialM . K.repeat
197FOLDABLE_INSTANCE(ZipSerialM)
198TRAVERSABLE_INSTANCE(ZipSerialM)
200------------------------------------------------------------------------------
201-- Parallely Zipping Streams
202------------------------------------------------------------------------------
204-- | Like 'ZipSerialM' but zips in parallel, it generates all the elements to
205-- be zipped concurrently.
208-- main = (toList . 'zipAsyncly' $ (,,) \<$\> s1 \<*\> s2 \<*\> s3) >>= print
209-- where s1 = fromFoldable [1, 2]
210-- s2 = fromFoldable [3, 4]
211-- s3 = fromFoldable [5, 6]
217-- The 'Semigroup' instance of this type works the same way as that of
221newtype ZipAsyncM m a = ZipAsyncM {getZipAsyncM :: Stream m a}
222 deriving (Semigroup, Monoid)
224-- | An IO stream whose applicative instance zips streams wAsyncly.
227type ZipAsync = ZipAsyncM IO
229-- | Fix the type of a polymorphic stream as 'ZipAsyncM'.
232zipAsyncly :: IsStream t => ZipAsyncM m a -> t m a
235-- | Same as 'zipAsyncly'.
238{-# DEPRECATED zippingAsync "Please use zipAsyncly instead." #-}
239zippingAsync :: IsStream t => ZipAsyncM m a -> t m a
240zippingAsync = zipAsyncly
242consMZipAsync :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
243consMZipAsync m ms = fromStream $ K.consMStream m (toStream ms)
245instance IsStream ZipAsyncM where
246 toStream = getZipAsyncM
247 fromStream = ZipAsyncM
250 {-# SPECIALIZE consM :: IO a -> ZipAsyncM IO a -> ZipAsyncM IO a #-}
251 consM :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
252 consM = consMZipAsync
255 {-# SPECIALIZE (|:) :: IO a -> ZipAsyncM IO a -> ZipAsyncM IO a #-}
256 (|:) :: Monad m => m a -> ZipAsyncM m a -> ZipAsyncM m a
259instance Monad m => Functor (ZipAsyncM m) where
261 fmap f (ZipAsyncM m) = D.fromStreamD $ D.mapM (return . f) $ D.toStreamD m
263instance MonadAsync m => Applicative (ZipAsyncM m) where
264 pure = ZipAsyncM . K.repeat
266 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