@@ -6,105 +6,72 @@
66-- Stability : experimental
77-- Portability : GHC
88--
9−-- Template Haskell macros to create useful stream types.
9+-- Template Haskell macros to create custom newtype wrappers for the 'Stream'
10+-- type, deriving all the usual instances.
1011--
11−-- __Create a type with a serial zipping applicative property:__
12+-- To use this module, "Streamly.Data.Stream" or "Streamly.Data.Stream.Prelude"
13+-- must be imported as "Stream". Also, it is recommended to import this module
14+-- unqualified to bring everything needed in scope without having to import
15+-- several other modules.
1216--
13−-- @
14−-- import Control.Monad.Catch (MonadThrow(..))
15−-- import Control.Monad.IO.Class (MonadIO(..))
16−-- import Control.Monad.Reader.Class (MonadReader(..))
17−-- import Control.Monad.Trans.Class (MonadTrans(..))
18−-- import Streamly.Data.Stream (Stream)
19−--
20−-- import qualified Streamly.Data.Stream
21−-- import qualified Streamly.Data.Stream as Stream
22−-- import qualified Streamly.Internal.Data.Stream.TypeGen as StreamTypeGen
23−--
24−-- applySerial :: Monad m => Stream m (a -> b) -> Stream m a -> Stream m b
25−-- applySerial = Stream.zipWith ($)
26−--
27−-- \$(StreamTypeGen.mkZippingType \"ZipSerial\" "applySerial" False)
28−-- @
29−--
30−-- __Create a type with a concurrent zipping applicative property:__
31−--
32−-- @
33−-- import Control.Monad.Catch (MonadThrow(..))
34−-- import Control.Monad.IO.Class (MonadIO(..))
35−-- import Control.Monad.Reader.Class (MonadReader(..))
36−-- import Control.Monad.Trans.Class (MonadTrans(..))
37−-- import Streamly.Data.Stream (Stream)
17+-- >>> import Control.Monad.Reader.Class (MonadReader(..))
18+-- >>> import qualified Streamly.Data.Stream.Prelude as Stream
19+-- >>> import Streamly.Internal.Data.Stream.TypeGen
3820--
39−-- import qualified Streamly.Data.Stream
40−-- import qualified Streamly.Data.Stream.Concurrent
41−-- import qualified Streamly.Data.Stream.Concurrent as Concur
42−-- import qualified Streamly.Internal.Data.Stream.TypeGen as StreamTypeGen
21+-- Instead of using these macros directly you could use the generated code as
22+-- well. Use these macros in ghci to generate the required code and paste it in
23+-- your package, you can customize it as you want. See the docs of the macros
24+-- below for examples of viewing the generated code.
4325--
44−-- applyConcurrent :: Monad m => Stream m (a -> b) -> Stream m a -> Stream m b
45−-- applyConcurrent = Concur.zipWith ($)
26+-- Example, create an applicative type with zipping apply:
4627--
47−-- \$(StreamTypeGen.mkZippingType \"ZipConcurrent\" "applyConcurrent" True)
48−-- @
28+-- >>> import Streamly.Data.Stream.Prelude (Stream)
29+-- >>> :{
30+-- zipApply :: Monad m => Stream m (a -> b) -> Stream m a -> Stream m b
31+-- zipApply = Stream.zipWith ($)
32+-- :}
4933--
50−-- __Create a type with serial interleave properties:__
34+-- > $(mkZipType "ZipStream" "zipApply" False)
5135--
52−-- @
53−-- import Control.Monad.Catch (MonadThrow(..))
54−-- import Control.Monad.IO.Class (MonadIO(..))
55−-- import Control.Monad.Reader.Class (MonadReader(..))
56−-- import Control.Monad.Trans.Class (MonadTrans(..))
57−-- import Streamly.Data.Stream (Stream)
36+-- Example, create an applicative type with concurrent zipping apply:
5837--
59−-- import qualified Control.Monad
60−-- import qualified Streamly.Data.Stream
61−-- import qualified Streamly.Data.Stream as Stream
62−-- import qualified Streamly.Internal.Data.Stream.TypeGen as StreamTypeGen
38+-- > $(mkZipType "ParZipStream" "parApply" True)
6339--
64−-- bindInterleave :: Stream m a -> (a -> Stream m b) -> Stream m b
65−-- bindInterleave = flip (Stream.concatMapWith Stream.interleave)
40+-- Example, create a monad type with an interleaving cross product bind:
6641--
67−-- \$(StreamTypeGen.mkNestingType \"InterleaveSerial\" "bindInterleave" False)
68−-- @
42+-- >>> :{
43+-- interleaveBind :: Stream m a -> (a -> Stream m b) -> Stream m b
44+-- interleaveBind = flip (Stream.concatMapWith Stream.interleave)
45+-- :}
6946--
70−-- __Create a type with eager concurrency properties:__
71−--
72−-- @
73−-- import Control.Monad.Catch (MonadThrow(..))
74−-- import Control.Monad.IO.Class (MonadIO(..))
75−-- import Control.Monad.Reader.Class (MonadReader(..))
76−-- import Control.Monad.Trans.Class (MonadTrans(..))
77−-- import Streamly.Data.Stream (Stream)
78−-- import Streamly.Data.Stream.Concurrent (MonadAsync)
47+-- > $(mkCrossType "InterleaveStream" "interleaveBind" False)
7948--
80−-- import qualified Control.Monad
81−-- import qualified Streamly.Data.Stream
82−-- import qualified Streamly.Data.Stream.Concurrent
83−-- import qualified Streamly.Data.Stream.Concurrent as Concur
84−-- import qualified Streamly.Internal.Data.Stream.TypeGen as StreamTypeGen
49+-- Example, create a monad type with an eager concurrent cross product bind:
8550--
86−-- bindConcurrent :: MonadAsync m => Stream m a -> (a -> Stream m b) -> Stream m b
87−-- bindConcurrent = flip (Concur.concatMapWith (Concur.eager True))
51+-- >>> :{
52+-- parBind :: Stream.MonadAsync m => Stream m a -> (a -> Stream m b) -> Stream m b
53+-- parBind = flip (Stream.parConcatMap (Stream.eager True))
54+-- :}
8855--
89−-- \$(StreamTypeGen.mkNestingType \"Parallel\" "bindConcurrent" True)
90−-- @
56+-- > $(mkCrossType "ParEagerStream" "parBind" True)
9157--
9258module Streamly.Internal.Data.Stream.TypeGen
93− ( mkZippingType
94− , mkNestingType
59+ (
60+ -- * Imports for Examples
61+ -- $setup
62+
63+ -- * Template Haskell Macros
64+ mkZipType
65+ , mkCrossType
66+
67+ -- * Re-exports
68+ , MonadIO(..)
69+ , MonadThrow(..)
70+ -- , MonadReader(..)
71+ , MonadTrans(..)
72+ , ap
9573 ) where
9674
97−--------------------------------------------------------------------------------
98−-- Developer notes
99−--------------------------------------------------------------------------------
100−
101−-- Debugging helpers,
102−--
103−-- >>> import Language.Haskell.TH
104−-- >>> import Streamly.Internal.Data.Stream.TypeGen
105−-- >>> expr <- runQ (mkNestingType "Parallel" "bindConcurrent" True)
106−-- >>> putStrLn $ pprint expr
107−
10875--------------------------------------------------------------------------------
10976-- Imports
11077--------------------------------------------------------------------------------
@@ -112,9 +79,20 @@ module Streamly.Internal.Data.Stream.TypeGen
11279import Language.Haskell.TH.Lib
11380import Language.Haskell.TH.Syntax
11481
82+import Control.Monad (ap)
83+import Control.Monad.Catch (MonadThrow(..))
84+import Control.Monad.IO.Class (MonadIO(..))
85+-- import Control.Monad.Reader.Class (MonadReader(..))
86+import Control.Monad.Trans.Class (MonadTrans(..))
87+import Prelude hiding (repeat)
88+
11589-- $setup
11690-- >>> :m
91+-- >>> :set -package mtl
92+-- >>> :set -package streamly
11793-- >>> import Language.Haskell.TH
94+-- >>> import Control.Monad.Reader.Class (MonadReader(..))
95+-- >>> import qualified Streamly.Data.Stream.Prelude as Stream
11896-- >>> import Streamly.Internal.Data.Stream.TypeGen
11997
12098--------------------------------------------------------------------------------
@@ -141,7 +119,7 @@ _r :: Name
141119_r = mkName "r"
142120
143121_Stream :: Name
144−_Stream = mkName "Stream"
122+_Stream = mkName "Stream.Stream"
145123
146124_fmap :: Name
147125_fmap = mkName "fmap"
@@ -451,50 +429,50 @@ mkSimpleStreamInstances dtNameStr = do
451429
452430-- | Create a type with a zip-like applicative.
453431--
454−-- >>> expr <- runQ (mkZippingType "ZipSerial" "apZipSerial" False)
432+-- >>> expr <- runQ (mkZipType "ZipStream" "zipApply" False)
455433-- >>> putStrLn $ pprint expr
456−-- newtype ZipSerial m a = ZipSerial (Stream m a)
457−-- mkZipSerial :: Stream m a -> ZipSerial m a
458−-- mkZipSerial = ZipSerial
459−-- unZipSerial :: ZipSerial m a -> Stream m a
460−-- unZipSerial (ZipSerial strm) = strm
461−-- instance Monad m => Functor (ZipSerial m)
434+-- newtype ZipStream m a = ZipStream (Stream.Stream m a)
435+-- mkZipStream :: Stream.Stream m a -> ZipStream m a
436+-- mkZipStream = ZipStream
437+-- unZipStream :: ZipStream m a -> Stream.Stream m a
438+-- unZipStream (ZipStream strm) = strm
439+-- instance Monad m => Functor (ZipStream m)
462440-- where {-# INLINE fmap #-}
463−-- fmap f (ZipSerial strm) = ZipSerial (fmap f strm)
464−-- instance Monad m => Applicative (ZipSerial m)
441+-- fmap f (ZipStream strm) = ZipStream (fmap f strm)
442+-- instance Monad m => Applicative (ZipStream m)
465443-- where {-# INLINE pure #-}
466−-- pure = ZipSerial . Streamly.Data.Stream.repeat
444+-- pure = ZipStream . Stream.repeat
467445-- {-# INLINE (<*>) #-}
468−-- (<*>) (ZipSerial strm1) (ZipSerial strm2) = ZipSerial (apZipSerial strm1 strm2)
469−-- instance MonadTrans ZipSerial
446+-- (<*>) (ZipStream strm1) (ZipStream strm2) = ZipStream (zipApply strm1 strm2)
447+-- instance MonadTrans ZipStream
470448-- where {-# INLINE lift #-}
471−-- lift = ZipSerial . lift
472−-- instance (Monad (ZipSerial m), MonadIO m) => MonadIO (ZipSerial m)
449+-- lift = ZipStream . lift
450+-- instance (Monad (ZipStream m), MonadIO m) => MonadIO (ZipStream m)
473451-- where {-# INLINE liftIO #-}
474−-- liftIO = ZipSerial . (lift . liftIO)
475−-- instance (Monad (ZipSerial m),
476−-- MonadThrow m) => MonadThrow (ZipSerial m)
452+-- liftIO = ZipStream . (lift . liftIO)
453+-- instance (Monad (ZipStream m),
454+-- MonadThrow m) => MonadThrow (ZipStream m)
477455-- where {-# INLINE throwM #-}
478−-- throwM = ZipSerial . (lift . throwM)
479−-- instance (Monad (ZipSerial m), MonadReader r m) => MonadReader r
480−-- (ZipSerial m)
456+-- throwM = ZipStream . (lift . throwM)
457+-- instance (Monad (ZipStream m), MonadReader r m) => MonadReader r
458+-- (ZipStream m)
481459-- where {-# INLINE ask #-}
482460-- ask = lift ask
483461-- {-# INLINE local #-}
484−-- local f (ZipSerial strm) = ZipSerial (local f strm)
485−mkZippingType
462+-- local f (ZipStream strm) = ZipStream (local f strm)
463+mkZipType
486464 :: String -- ^ Name of the type
487465 -> String -- ^ Function to use for (\<*\>)
488− -> Bool -- ^ 'True' if (\<*\>) has concurrent properties
466+ -> Bool -- ^ 'True' if (\<*\>) requires MonadAsync constraint (concurrent)
489467 -> Q [Dec]
490−mkZippingType dtNameStr apOpStr isConcurrent = do
468+mkZipType dtNameStr apOpStr isConcurrent = do
491469 typeDec <- makeTypeDec dtNameStr
492470 functorI <- makeStreamFunctor dtNameStr
493471 applicativeI <-
494472 mkStreamApplicative
495473 dtNameStr
496474 classConstraints
497− "Streamly.Data.Stream.repeat"
475+ "Stream.repeat"
498476 apOpStr
499477 simpleInstances <- mkSimpleStreamInstances dtNameStr
500478 return $ typeDec ++ [functorI, applicativeI] ++ simpleInstances
@@ -503,30 +481,30 @@ mkZippingType dtNameStr apOpStr isConcurrent = do
503481
504482 classConstraints =
505483 if isConcurrent
506− then ["Streamly.Data.Stream.Concurrent.MonadAsync"]
484+ then ["Stream.MonadAsync"]
507485 else ["Monad"]
508486
509487-- | Create a type with specific stream combination properties.
510488--
511−-- >>> expr <- runQ (mkNestingType "Parallel" "bindConcurrent" True)
489+-- >>> expr <- runQ (mkCrossType "Parallel" "parBind" True)
512490-- >>> putStrLn $ pprint expr
513−-- newtype Parallel m a = Parallel (Stream m a)
514−-- mkParallel :: Stream m a -> Parallel m a
491+-- newtype Parallel m a = Parallel (Stream.Stream m a)
492+-- mkParallel :: Stream.Stream m a -> Parallel m a
515493-- mkParallel = Parallel
516−-- unParallel :: Parallel m a -> Stream m a
494+-- unParallel :: Parallel m a -> Stream.Stream m a
517495-- unParallel (Parallel strm) = strm
518496-- instance Monad m => Functor (Parallel m)
519497-- where {-# INLINE fmap #-}
520498-- fmap f (Parallel strm) = Parallel (fmap f strm)
521−-- instance Streamly.Data.Stream.Concurrent.MonadAsync m => Monad (Parallel m)
499+-- instance Stream.MonadAsync m => Monad (Parallel m)
522500-- where {-# INLINE (>>=) #-}
523501-- (>>=) (Parallel strm1) f = let f1 a = unParallel (f a)
524−-- in Parallel (bindConcurrent strm1 f1)
525−-- instance Streamly.Data.Stream.Concurrent.MonadAsync m => Applicative (Parallel m)
502+-- in Parallel (parBind strm1 f1)
503+-- instance Stream.MonadAsync m => Applicative (Parallel m)
526504-- where {-# INLINE pure #-}
527−-- pure = Parallel . Streamly.Data.Stream.fromPure
505+-- pure = Parallel . Stream.fromPure
528506-- {-# INLINE (<*>) #-}
529−-- (<*>) (Parallel strm1) (Parallel strm2) = Parallel (Control.Monad.ap strm1 strm2)
507+-- (<*>) (Parallel strm1) (Parallel strm2) = Parallel (ap strm1 strm2)
530508-- instance MonadTrans Parallel
531509-- where {-# INLINE lift #-}
532510-- lift = Parallel . lift
@@ -543,12 +521,12 @@ mkZippingType dtNameStr apOpStr isConcurrent = do
543521-- ask = lift ask
544522-- {-# INLINE local #-}
545523-- local f (Parallel strm) = Parallel (local f strm)
546−mkNestingType
524+mkCrossType
547525 :: String -- ^ Name of the type
548526 -> String -- ^ Function to use for (>>=)
549− -> Bool -- ^ 'True' if (>>=) has concurrent properties
527+ -> Bool -- ^ 'True' if (>>=) requires MonadAsync constraint (concurrent)
550528 -> Q [Dec]
551−mkNestingType dtNameStr bindOpStr isConcurrent = do
529+mkCrossType dtNameStr bindOpStr isConcurrent = do
552530 typeDec <- makeTypeDec dtNameStr
553531 functorI <- makeStreamFunctor dtNameStr
554532 monadI <- mkStreamMonad dtNameStr classConstraints bindOpStr
@@ -556,8 +534,8 @@ mkNestingType dtNameStr bindOpStr isConcurrent = do
556534 mkStreamApplicative
557535 dtNameStr
558536 classConstraints
559− "Streamly.Data.Stream.fromPure"
560− "Control.Monad.ap"
537+ "Stream.fromPure"
538+ "ap"
561539 simpleInstances <- mkSimpleStreamInstances dtNameStr
562540 return $ typeDec ++ [functorI, monadI, applicativeI] ++ simpleInstances
563541
@@ -565,5 +543,5 @@ mkNestingType dtNameStr bindOpStr isConcurrent = do
565543
566544 classConstraints =
567545 if isConcurrent
568− then ["Streamly.Data.Stream.Concurrent.MonadAsync"]
546+ then ["Stream.MonadAsync"]
569547 else ["Monad"]