on 0258d77 help sign in
streamly/src/Streamly/Streams/StreamKType.hs
342 lines 11 kB history raw
1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE CPP #-}
3{-# LANGUAGE ConstraintKinds #-}
4{-# LANGUAGE FlexibleContexts #-}
5{-# LANGUAGE FlexibleInstances #-}
6{-# LANGUAGE InstanceSigs #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE PatternSynonyms #-}
9{-# LANGUAGE ViewPatterns #-}
10{-# LANGUAGE RankNTypes #-}
11{-# LANGUAGE UndecidableInstances #-} -- XXX
13-- |
14-- Module : Streamly.Streams.StreamKType
15-- Copyright : (c) 2017 Harendra Kumar
16--
17-- License : BSD3
18-- Maintainer : harendra.kumar@gmail.com
19-- Stability : experimental
20-- Portability : GHC
21--
22--
23-- Continuation passing style (CPS) stream implementation. The symbol 'K' below
24-- denotes a function as well as a Kontinuation.
25--
26module Streamly.Streams.StreamKType
27 (
28 -- * A class for streams
29 IsStream (..)
30 , adapt
32 -- * The stream type
33 , Stream ()
35 -- * Construction
36 , mkStream
38 -- * Elimination
39 , foldStream
40 , foldStreamShared
41 , foldStreamSVar
43 -- instances
44 , consMSerial
45 , nil
46 , serial
47 , map
48 , yieldM
50 , Streaming -- deprecated
51 )
52where
54import Control.Monad (void)
55import Control.Monad.IO.Class (MonadIO(liftIO))
56import Control.Monad.Trans.Class (MonadTrans(lift))
57import Data.Semigroup (Semigroup(..))
58import Prelude hiding (map)
60import Streamly.SVar
62------------------------------------------------------------------------------
63-- Types that can behave as a Stream
64------------------------------------------------------------------------------
66infixr 5 `consM`
67infixr 5 |:
69-- XXX Use a different SVar based on the stream type. But we need to make sure
70-- that we do not lose performance due to polymorphism.
71--
72-- | Class of types that can represent a stream of elements of some type 'a' in
73-- some monad 'm'.
74--
75-- @since 0.2.0
76class IsStream t where
77 toStream :: t m a -> Stream m a
78 fromStream :: Stream m a -> t m a
79 -- | Constructs a stream by adding a monadic action at the head of an
80 -- existing stream. For example:
81 --
82 -- @
83 -- > toList $ getLine \`consM` getLine \`consM` nil
84 -- hello
85 -- world
86 -- ["hello","world"]
87 -- @
88 --
89 -- /Concurrent (do not use 'parallely' to construct infinite streams)/
90 --
91 -- @since 0.2.0
92 consM :: MonadAsync m => m a -> t m a -> t m a
93 -- | Operator equivalent of 'consM'. We can read it as "@parallel colon@"
94 -- to remember that @|@ comes before ':'.
95 --
96 -- @
97 -- > toList $ getLine |: getLine |: nil
98 -- hello
99 -- world
100 -- ["hello","world"]
101 -- @
102 --
103 -- @
104 -- let delay = threadDelay 1000000 >> print 1
105 -- runStream $ serially $ delay |: delay |: delay |: nil
106 -- runStream $ parallely $ delay |: delay |: delay |: nil
107 -- @
108 --
109 -- /Concurrent (do not use 'parallely' to construct infinite streams)/
110 --
111 -- @since 0.2.0
112 (|:) :: MonadAsync m => m a -> t m a -> t m a
113 -- We can define (|:) just as 'consM' but it is defined explicitly for each
114 -- type because we want to use SPECIALIZE pragma on the definition.
116-- | Same as 'IsStream'.
117--
118-- @since 0.1.0
119{-# DEPRECATED Streaming "Please use IsStream instead." #-}
120type Streaming = IsStream
122-------------------------------------------------------------------------------
123-- Type adapting combinators
124-------------------------------------------------------------------------------
126-- XXX Move/reset the State here by reconstructing the stream with cleared
127-- state. Can we make sure we do not do that when t1 = t2? If we do this then
128-- we do not need to do that explicitly using svarStyle. It would act as
129-- unShare when the stream type is the same.
130--
131-- | Adapt any specific stream type to any other specific stream type.
132--
133-- @since 0.1.0
134adapt :: (IsStream t1, IsStream t2) => t1 m a -> t2 m a
135adapt = fromStream . toStream
137------------------------------------------------------------------------------
138-- Basic stream type
139------------------------------------------------------------------------------
141-- | The type @Stream m a@ represents a monadic stream of values of type 'a'
142-- constructed using actions in monad 'm'. It uses stop, singleton and yield
143-- continuations equivalent to the following direct style type:
144--
145-- @
146-- data Stream m a = Stop | Singleton a | Yield a (Stream m a)
147-- @
148--
149-- To facilitate parallel composition we maintain a local state in an 'SVar'
150-- that is shared across and is used for synchronization of the streams being
151-- composed.
152--
153-- The singleton case can be expressed in terms of stop and yield but we have
154-- it as a separate case to optimize composition operations for streams with
155-- single element. We build singleton streams in the implementation of 'pure'
156-- for Applicative and Monad, and in 'lift' for MonadTrans.
157--
158-- XXX remove the Stream type parameter from State as it is always constant.
159-- We can remove it from SVar as well
160--
161newtype Stream m a =
162 MkStream (forall r.
163 State Stream m a -- state
164 -> m r -- stop
165 -> (a -> m r) -- singleton
166 -> (a -> Stream m a -> m r) -- yield
167 -> m r
168 )
170------------------------------------------------------------------------------
171-- Building a stream
172------------------------------------------------------------------------------
174-- XXX The State is always parameterized by "Stream" which means State is not
175-- different for different stream types. So we have to manually make sure that
176-- when converting from one stream to another we migrate the state correctly.
177-- This can be fixed if we use a different SVar type for different streams.
178-- Currently we always use "SVar Stream" and therefore a different State type
179-- parameterized by that stream.
180--
181-- XXX change the order of arguments to match the standard fold function
182-- convention i.e. st yield single stop.
183--
184-- | Build a stream from an 'SVar', a stop continuation, a singleton stream
185-- continuation and a yield continuation.
186mkStream:: IsStream t
187 => (forall r. State Stream m a
188 -> m r
189 -> (a -> m r)
190 -> (a -> t m a -> m r)
191 -> m r)
192 -> t m a
193mkStream k = fromStream $ MkStream $ \st stp sng yld ->
194 let yieldk a r = yld a (toStream r)
195 in k st stp sng yieldk
197------------------------------------------------------------------------------
198-- Folding a stream
199------------------------------------------------------------------------------
201-- | Fold a stream by providing an SVar, a stop continuation, a singleton
202-- continuation and a yield continuation. The stream would share the current
203-- SVar passed via the State.
204{-# INLINE foldStreamShared #-}
205foldStreamShared
206 :: IsStream t
207 => State Stream m a
208 -> m r
209 -> (a -> m r)
210 -> (a -> t m a -> m r)
211 -> t m a
212 -> m r
213foldStreamShared st stp sng yld m =
214 let yieldk a x = yld a (fromStream x)
215 MkStream k = toStream m
216 in k st stp sng yieldk
218-- | Fold a stream by providing a State, stop continuation, a singleton
219-- continuation and a yield continuation. The stream will not use the SVar
220-- passed via State.
221{-# INLINE foldStream #-}
222foldStream
223 :: IsStream t
224 => State Stream m a
225 -> m r
226 -> (a -> m r)
227 -> (a -> t m a -> m r)
228 -> t m a
229 -> m r
230foldStream st stp sng yld m =
231 let yieldk a x = yld a (fromStream x)
232 MkStream k = toStream m
233 in k (adaptState st) stp sng yieldk
235-- Run the stream using a run function associated with the SVar that runs the
236-- streams with a captured snapshot of the monadic state.
237{-# INLINE foldStreamSVar #-}
238foldStreamSVar
239 :: (IsStream t, MonadIO m)
240 => SVar Stream m a
241 -> State Stream m a -- state
242 -> m r -- stop
243 -> (a -> m r) -- singleton
244 -> (a -> t m a -> m r) -- yield
245 -> t m a
246 -> m ()
247foldStreamSVar sv st stp sng yld m =
248 let mrun = runInIO $ svarMrun sv
249 in void $ liftIO $ mrun $ foldStreamShared st stp sng yld m
251-------------------------------------------------------------------------------
252-- Instances
253-------------------------------------------------------------------------------
255{-# INLINE consMSerial #-}
256consMSerial :: (IsStream t, Monad m) => m a -> t m a -> t m a
257consMSerial m r = mkStream $ \_ _ _ yld -> m >>= \a -> yld a r
259-------------------------------------------------------------------------------
260-- IsStream Stream
261-------------------------------------------------------------------------------
263instance IsStream Stream where
264 toStream = id
265 fromStream = id
267 {-# INLINE consM #-}
268 {-# SPECIALIZE consM :: IO a -> Stream IO a -> Stream IO a #-}
269 consM :: Monad m => m a -> Stream m a -> Stream m a
270 consM = consMSerial
272 {-# INLINE (|:) #-}
273 {-# SPECIALIZE (|:) :: IO a -> Stream IO a -> Stream IO a #-}
274 (|:) :: Monad m => m a -> Stream m a -> Stream m a
275 (|:) = consMSerial
277------------------------------------------------------------------------------
278-- Semigroup
279------------------------------------------------------------------------------
281-- | Polymorphic version of the 'Semigroup' operation '<>' of 'SerialT'.
282-- Appends two streams sequentially, yielding all elements from the first
283-- stream, and then all elements from the second stream.
284--
285-- @since 0.2.0
286{-# INLINE serial #-}
287serial :: IsStream t => t m a -> t m a -> t m a
288serial m1 m2 = go m1
289 where
290 go m = mkStream $ \st stp sng yld ->
291 let stop = foldStream st stp sng yld m2
292 single a = yld a m2
293 yieldk a r = yld a (go r)
294 in foldStream st stop single yieldk m
296instance Semigroup (Stream m a) where
297 (<>) = serial
299------------------------------------------------------------------------------
300-- Monoid
301------------------------------------------------------------------------------
303-- | An empty stream.
304--
305-- @
306-- > toList nil
307-- []
308-- @
309--
310-- @since 0.1.0
311nil :: IsStream t => t m a
312nil = mkStream $ \_ stp _ _ -> stp
314instance Monoid (Stream m a) where
315 mempty = nil
316 mappend = (<>)
318-------------------------------------------------------------------------------
319-- Functor
320-------------------------------------------------------------------------------
323{-# INLINE map #-}
324map :: (IsStream t, Monad m) => (a -> b) -> t m a -> t m b
325map f m = mkStream $ \st stp sng yld ->
326 let single = sng . f
327 yieldk a r = yld (f a) (map f r)
328 in foldStream (adaptState st) stp single yieldk m
330instance Monad m => Functor (Stream m) where
331 fmap = map
333-------------------------------------------------------------------------------
334-- Transformers
335-------------------------------------------------------------------------------
337{-# INLINE yieldM #-}
338yieldM :: (Monad m, IsStream t) => m a -> t m a
339yieldM m = fromStream $ mkStream $ \_ _ single _ -> m >>= single
341instance MonadTrans Stream where
342 lift = yieldM