Template Haskell macros to create custom newtype wrappers for the Stream
type. See the examples below to create the standard stream types that were
available in streamly versions before 0.9.0.
To use this module, the following extensions must be enabled:
Import this module unqualified to bring everything needed in scope without
having to import several other modules. Also, Streamly.Data.Stream or
Streamly.Data.Stream.Prelude must be imported as Stream.
Example2 expressions
>>> import Streamly.Data.Stream.MkType>>> import qualified Streamly.Data.Stream.Prelude as Stream
For Streamly.Prelude.AsyncT monad type with a concurrent cross product
bind:
For Streamly.Prelude.ZipAsync concurrent zipping applicative type:
Example1 expression
>>> :{ parApply = Stream.parApply id $(mkZipType "ZipAsync" "parApply" True):}
Instead of using these macros directly you could use the generated code as
well. Use these macros in ghci to generate the required code and paste it in
your package, you can customize the code as desired. See the docs of the
macros below for examples about how to view the generated code. For example:
>>> expr <- runQ (mkZipType "ZipStream" "zipApply" False)>>> putStrLn $ pprint exprnewtype ZipStream m a = ZipStream (Stream.Stream m a) deriving FoldablemkZipStream :: Stream.Stream m a -> ZipStream m amkZipStream = ZipStreamunZipStream :: ZipStream m a -> Stream.Stream m aunZipStream (ZipStream strm) = strmderiving instance IsList (ZipStream Identity a)deriving instance a ~ GHC.Types.Char => IsString (ZipStream Identity a)deriving instance GHC.Classes.Eq a => Eq (ZipStream Identity a)deriving instance GHC.Classes.Ord a => Ord (ZipStream Identity a)instance Show a => Show (ZipStream Identity a) where {{-# INLINE show #-}; show (ZipStream strm) = show strm}instance Read a => Read (ZipStream Identity a) where {{-# INLINE readPrec #-}; readPrec = fmap ZipStream readPrec}instance Monad m => Functor (ZipStream m) where {{-# INLINE fmap #-}; fmap f (ZipStream strm) = ZipStream (fmap f strm)}instance Monad m => Applicative (ZipStream m) where {{-# INLINE pure #-}; pure = ZipStream . Stream.repeat; {-# INLINE (<*>) #-}; (<*>) (ZipStream strm1) (ZipStream strm2) = ZipStream (zipApply strm1 strm2)}
Create a type with specific stream combination properties.
Example2 expressions
>>> expr <- runQ (mkCrossType "Parallel" "parBind" True)>>> putStrLn $ pprint exprnewtype Parallel m a = Parallel (Stream.Stream m a)mkParallel :: Stream.Stream m a -> Parallel m amkParallel = ParallelunParallel :: Parallel m a -> Stream.Stream m aunParallel (Parallel strm) = strminstance Monad m => Functor (Parallel m) where {{-# INLINE fmap #-}; fmap f (Parallel strm) = Parallel (fmap f strm)}instance Stream.MonadAsync m => Monad (Parallel m) where {{-# INLINE (>>=) #-}; (>>=) (Parallel strm1) f = let f1 a = unParallel (f a) in Parallel (parBind strm1 f1)}instance Stream.MonadAsync m => Applicative (Parallel m) where {{-# INLINE pure #-}; pure = Parallel . Stream.fromPure; {-# INLINE (<*>) #-}; (<*>) = ap}instance (Monad (Parallel m), MonadIO m) => MonadIO (Parallel m) where {{-# INLINE liftIO #-}; liftIO = Parallel . (Stream.fromEffect . liftIO)}instance (Monad (Parallel m), MonadThrow m) => MonadThrow (Parallel m) where {{-# INLINE throwM #-}; throwM = Parallel . (Stream.fromEffect . throwM)}
Derived instances of Read make the following assumptions, which
derived instances of Text.Show.Show obey:
If the constructor is defined to be an infix operator, then the
derived Read instance will parse only infix applications of
the constructor (not the prefix form).
Associativity is not used to reduce the occurrence of parentheses,
although precedence may be.
If the constructor is defined using record syntax, the derived Read
will parse only the record-syntax form, and furthermore, the fields
must be given in the same order as the original declaration.
The derived Read instance allows arbitrary Haskell whitespace
between tokens of the input string. Extra parentheses are also
allowed.
For example, given the declarations
infixr 5 :^:
data Tree a = Leaf a | Tree a :^: Tree a
the derived instance of Read in Haskell 2010 is equivalent to
instance (Read a) => Read (Tree a) where
readsPrec d r = readParen (d > app_prec)
(\r -> [(Leaf m,t) |
("Leaf",s) <- lex r,
(m,t) <- readsPrec (app_prec+1) s]) r
++ readParen (d > up_prec)
(\r -> [(u:^:v,w) |
(u,s) <- readsPrec (up_prec+1) r,
(":^:",t) <- lex s,
(v,w) <- readsPrec (up_prec+1) t]) r
where app_prec = 10
up_prec = 5
Note that right-associativity of :^: is unused.
The derived instance in GHC is equivalent to
instance (Read a) => Read (Tree a) where
readPrec = parens $ (prec app_prec $ do
Ident "Leaf" <- lexP
m <- step readPrec
return (Leaf m))
+++ (prec up_prec $ do
u <- step readPrec
Symbol ":^:" <- lexP
v <- step readPrec
return (u :^: v))
where app_prec = 10
up_prec = 5
readListPrec = readListPrecDefault
Why do both readsPrec and readPrec exist, and why does GHC opt to
implement readPrec in derived Read instances instead of readsPrec?
The reason is that readsPrec is based on the ReadS type, and although
ReadS is mentioned in the Haskell 2010 Report, it is not a very efficient
parser data structure.
readPrec, on the other hand, is based on a much more efficient ReadPrec
datatype (a.k.a "new-style parsers"), but its definition relies on the use
of the RankNTypes language extension. Therefore, readPrec (and its
cousin, readListPrec) are marked as GHC-only. Nevertheless, it is
recommended to use readPrec instead of readsPrec whenever possible
for the efficiency improvements it brings.
As mentioned above, derived Read instances in GHC will implement
readPrec instead of readsPrec. The default implementations of
readsPrec (and its cousin, readList) will simply use readPrec under
the hood. If you are writing a Read instance by hand, it is recommended
to write it like so:
attempts to parse a value from the front of the string, returning
a list of (parsed value, remaining string) pairs. If there is no
successful parse, the returned list is empty.
Derived instances of Read and Text.Show.Show satisfy the following:
The method readList is provided to allow the programmer to
give a specialised way of parsing lists of values.
For example, this is used by the predefined Read instance of
the Char type, where values of type String are expected to
use double quotes, rather than square brackets.
ReadTextDefined in text-2.1.3 · Data.Text · orphan
ReadTextDefined in text-2.1.3 · Data.Text.Lazy · orphan
ReadFPFormatDefined in text-2.1.3 · Data.Text.Lazy.Builder.RealFloat
ReadDayDefined in time-1.12.2 · Data.Time.Format.Parse · orphan
ReadMonthDefined in time-1.12.2 · Data.Time.Calendar.Month
Read as yyyy-mm.
ReadQuarterDefined in time-1.12.2 · Data.Time.Calendar.Quarter
Read as yyyy-Qn.
ReadQuarterOfYearDefined in time-1.12.2 · Data.Time.Calendar.Quarter
ReadDayOfWeekDefined in time-1.12.2 · Data.Time.Calendar.Week
ReadDiffTimeDefined in time-1.12.2 · Data.Time.Clock.Internal.DiffTime
ReadNominalDiffTimeDefined in time-1.12.2 · Data.Time.Clock.Internal.NominalDiffTime
ReadUTCTimeDefined in time-1.12.2 · Data.Time.Format.Parse · orphan
ReadUniversalTimeDefined in time-1.12.2 · Data.Time.Format.Parse · orphan
ReadLocalTimeDefined in time-1.12.2 · Data.Time.Format.Parse · orphan
ReadTimeOfDayDefined in time-1.12.2 · Data.Time.Format.Parse · orphan
ReadTimeZoneDefined in time-1.12.2 · Data.Time.Format.Parse · orphan
This only works for ±HHMM format,
single-letter military time-zones,
and these time-zones: "UTC", "UT", "GMT", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT",
per RFC 822 section 5.
ReadZonedTimeDefined in time-1.12.2 · Data.Time.Format.Parse · orphan
This only works for a zonedTimeZone in ±HHMM format,
single-letter military time-zones,
and these time-zones: "UTC", "UT", "GMT", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT",
per RFC 822 section 5.
ReadRTLDFlagsDefined in unix-2.8.7.0 · System.Posix.DynamicLinker.Prim
ReadCAttributesDefined in unix-2.8.7.0 · System.Posix.Files.Common
ReadStatxFlagsDefined in unix-2.8.7.0 · System.Posix.Files.Common
ReadStatxMaskDefined in unix-2.8.7.0 · System.Posix.Files.Common
Monads in which IO computations may be embedded.
Any monad built by applying a sequence of monad transformers to the
IO monad will be an instance of this class.
Instances should satisfy the following laws, which state that liftIO
is a transformer of monads:
Lift a computation from the IO monad.
This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations
(i.e. IO is the base monad for the stack).
Example
import Control.Monad.Trans.State -- from the "transformers" library
printState :: Show s => StateT s IO ()
printState = do
state <- get
liftIO $ print state
Had we omitted liftIO, we would have ended up with this error:
• Couldn't match type ‘IO’ with ‘StateT s IO’
Expected type: StateT s IO ()
Actual type: IO ()
The important part here is the mismatch between StateT s IO () and IO ().
Luckily, we know of a function that takes an IO a and returns an (m a): liftIO,
enabling us to run the program and see the expected results:
Throw an exception. Note that this throws when this action is run in
the monad m, not when it is applied. It is a generalization of
Control.Exception's throwIO.
Should satisfy the law:
throwM e >> f = throwM e
Instances27MonadThrow, …
MonadThrowSTMDefined in exceptions-0.10.9 · Control.Monad.Catch
MonadThrowMaybeDefined in exceptions-0.10.9 · Control.Monad.Catch
MonadThrowIODefined in exceptions-0.10.9 · Control.Monad.Catch
MonadThrowQDefined in exceptions-0.10.9 · Control.Monad.Catch
MonadThrow []Defined in exceptions-0.10.9 · Control.Monad.Catch
MonadThrow (STs)Defined in exceptions-0.10.9 · Control.Monad.Catch
The class of monad transformers.
For any monad m, the result t m should also be a monad,
and lift should be a monad transformation from m to t m,
i.e. it should satisfy the following laws:
Since 0.6.0.0 and for GHC 8.6 and later, the requirement that t m
be a Monad is enforced by the implication constraint
forall m. Monad m => Monad (t m) enabled by the
QuantifiedConstraints extension.