1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE ScopedTypeVariables #-}
4-------------------------------------------------------------------------------
5-- Combining control flow manipulating monad transformers (MaybeT, exceptT,
7-------------------------------------------------------------------------------
9-- Streamly streams are non-determinism (nested looping) monads. We can use a
10-- control flow monad on top or streamly on top depending on whether we want to
11-- superimpose control flow manipulation on top of non-deterministic
12-- composition or vice-versa.
14-- This file provides an example where we enter a sequence of characters "x",
15-- and "y" on separate lines, on the command line. When any other sequence is
16-- entered the control flow short circuits at the first non-matching char and
19import Control.Concurrent (threadDelay)
20import Control.Exception (catch, SomeException)
22import Control.Monad.Catch (MonadThrow, throwM, Exception)
23import Control.Monad.IO.Class
24import Control.Monad.Trans.Class
25import Control.Monad.Trans.Maybe
26import Control.Monad.Trans.Except
27import Control.Monad.Trans.Cont
29import qualified Streamly.Prelude as S
31-------------------------------------------------------------------------------
32-- Using MaybeT below streamly
33-------------------------------------------------------------------------------
35-- When streamly is on top MaybeT would terminate all iterations of
42 , Applicative (t (MaybeT m))
43 , MonadIO (t (MaybeT m))
46getSequenceMaybeBelow = do
47 liftIO $ putStrLn "MaybeT below streamly: Enter one char per line: "
49 i <- S.fromFoldable [1..2 :: Int]
50 liftIO $ putStrLn $ "iteration = " <> show i
53 when (r1 /= "x") $ lift mzero
56 when (r2 /= "y") $ lift mzero
58mainMaybeBelow :: IO ()
60 r <- runMaybeT (S.drain getSequenceMaybeBelow)
62 Just _ -> putStrLn "Bingo"
63 Nothing -> putStrLn "Wrong"
65-------------------------------------------------------------------------------
66-- Using MaybeT above streamly
67-------------------------------------------------------------------------------
69-- When MaybeT is on top a Nothing would terminate only the current iteration
70-- of non-determinism below.
72-- Note that this is redundant configuration as the same behavior can be
73-- acheived with just streamly, using mzero.
75getSequenceMaybeAbove :: (IsStream t, MonadIO (t m)) => MaybeT (t m) ()
76getSequenceMaybeAbove = do
77 liftIO $ putStrLn "MaybeT above streamly: Enter one char per line: "
79 i <- lift $ S.fromFoldable [1..2 :: Int]
80 liftIO $ putStrLn $ "iteration = " <> show i
83 when (r1 /= "x") mzero
86 when (r2 /= "y") mzero
88mainMaybeAbove :: (IsStream t, MonadIO (t m)) => MaybeT (t m) ()
91 liftIO $ putStrLn "Bingo"
93-------------------------------------------------------------------------------
94-- Using ExceptT below streamly
95-------------------------------------------------------------------------------
97-- XXX need to have a specialized liftCatch to lift catchE
99-- Note that throwE would terminate all iterations of non-determinism
101getSequenceEitherBelow
106 , MonadIO (t (ExceptT String m))
108 => t (ExceptT String m) ()
109getSequenceEitherBelow = do
110 liftIO $ putStrLn "ExceptT below streamly: Enter one char per line: "
112 i <- S.fromFoldable [1..2 :: Int]
113 liftIO $ putStrLn $ "iteration = " <> show i
116 when (r1 /= "x") $ lift $ throwE $ "Expecting x got: " <> r1
119 when (r2 /= "y") $ lift $ throwE $ "Expecting y got: " <> r2
121mainEitherBelow :: IO ()
123 -- XXX Cannot lift catchE
124 r <- runExceptT (S.drain getSequenceEitherBelow)
126 Right _ -> liftIO $ putStrLn "Bingo"
127 Left s -> liftIO $ putStrLn s
129-------------------------------------------------------------------------------
130-- Using ExceptT below concurrent streamly
131-------------------------------------------------------------------------------
133-- XXX does not work correctly yet
135getSequenceEitherAsyncBelow
141 , MonadIO (t (ExceptT String m))
142 , Semigroup (t (ExceptT String m) Integer)
144 => t (ExceptT String m) ()
145getSequenceEitherAsyncBelow = do
146 liftIO $ putStrLn "ExceptT below concurrent streamly: "
148 i <- (liftIO (threadDelay 1000)
149 >> lift (throwE "First task")
151 <> (lift (throwE "Second task") >> return 2)
152 <> S.yield (3 :: Integer)
153 liftIO $ putStrLn $ "iteration = " <> show i
155mainEitherAsyncBelow :: IO ()
156mainEitherAsyncBelow = do
157 r <- runExceptT (S.drain $ asyncly getSequenceEitherAsyncBelow)
159 Right _ -> liftIO $ putStrLn "Bingo"
160 Left s -> liftIO $ putStrLn s
162-------------------------------------------------------------------------------
163-- Using ExceptT above streamly
164-------------------------------------------------------------------------------
166-- When ExceptT is on top, we can lift the non-determinism of stream from
169-- Note that throwE would terminate/break only current iteration of
170-- non-determinism and not all of them altogether.
172-- Here we can use catchE directly but will have to use monad-control to lift
173-- stream operations with stream arguments.
174getSequenceEitherAbove :: (IsStream t, Monad m, MonadIO (t m))
175 => ExceptT String (t m) ()
176getSequenceEitherAbove = do
177 liftIO $ putStrLn "ExceptT above streamly: Enter one char per line: "
179 i <- lift $ S.fromFoldable [1..2 :: Int]
180 liftIO $ putStrLn $ "iteration = " <> show i
183 when (r1 /= "x") $ throwE $ "Expecting x got: " <> r1
186 when (r2 /= "y") $ throwE $ "Expecting y got: " <> r2
188mainEitherAbove :: (IsStream t, Monad m, MonadIO (t m))
189 => ExceptT String (t m) ()
191 catchE (getSequenceEitherAbove >> liftIO (putStrLn "Bingo"))
194-------------------------------------------------------------------------------
195-- Using MonadThrow to throw exceptions in streamly
196-------------------------------------------------------------------------------
198newtype Unexpected = Unexpected String deriving Show
200instance Exception Unexpected
202-- Note that unlike when ExceptT is used on top, MonadThrow terminates all
203-- iterations of non-determinism rather then just the current iteration.
205getSequenceMonadThrow :: (IsStream t, Monad m, MonadIO (t m), MonadThrow (t m))
207getSequenceMonadThrow = do
208 liftIO $ putStrLn "MonadThrow in streamly: Enter one char per line: "
210 i <- S.fromFoldable [1..2 :: Int]
211 liftIO $ putStrLn $ "iteration = " <> show i
214 when (r1 /= "x") $ throwM $ Unexpected $ "Expecting x got: " <> r1
217 when (r2 /= "y") $ throwM $ Unexpected $ "Expecting y got: " <> r2
219mainMonadThrow :: IO ()
221 catch (S.drain getSequenceMonadThrow >> liftIO (putStrLn "Bingo"))
222 (\(e :: SomeException) -> liftIO $ print e)
224-------------------------------------------------------------------------------
225-- Using ContT below streamly
226-------------------------------------------------------------------------------
228-- CallCC is the goto/setjmp/longjmp equivalent
229-- Allows us to manipulate the control flow in arbitrary ways
231-- XXX need to have a specialized liftCallCC to actually lift callCC
234 :: (IsStream t, MonadTrans t, MonadIO m, MonadIO (t (ContT r m)))
235 => t (ContT r m) (Either String ())
236getSequenceContBelow = do
237 liftIO $ putStrLn "ContT below streamly: Enter one char per line: "
239 i <- S.fromFoldable [1..2 :: Int]
240 liftIO $ putStrLn $ "iteration = " <> show i
242 r <- lift $ callCC $ \exit -> do
245 then exit $ Left $ "Expecting x got: " <> r1
246 else return $ Right ()
250 then exit $ Left $ "Expecting y got: " <> r2
251 else return $ Right ()
252 liftIO $ putStrLn $ "done iteration = " <> show i
256 :: (IsStream t, MonadIO m, MonadTrans t, MonadIO (t (ContT r m)))
259 r <- getSequenceContBelow
261 Right _ -> liftIO $ putStrLn "Bingo"
262 Left s -> liftIO $ putStrLn s
264-------------------------------------------------------------------------------
265-- Using ContT above streamly
266-------------------------------------------------------------------------------
268getSequenceContAbove :: (IsStream t, Monad m, MonadIO (t m))
269 => ContT r (t m) (Either String ())
270getSequenceContAbove = do
271 liftIO $ putStrLn "ContT above streamly: Enter one char per line: "
273 i <- lift $ S.fromFoldable [1..2 :: Int]
274 liftIO $ putStrLn $ "iteration = " <> show i
279 then exit $ Left $ "Expecting x got: " <> r1
280 else return $ Right ()
284 then exit $ Left $ "Expecting y got: " <> r2
285 else return $ Right ()
287mainContAbove :: (IsStream t, Monad m, MonadIO (t m)) => ContT r (t m) ()
289 r <- getSequenceContAbove
291 Right _ -> liftIO $ putStrLn "Bingo"
292 Left s -> liftIO $ putStrLn s
294-------------------------------------------------------------------------------
295-- Combining control flow manipulating monad transformers (MaybeT, exceptT,
296-- ContT) with Streamly
297-------------------------------------------------------------------------------
302 S.drain $ runMaybeT mainMaybeAbove
303 runContT (S.drain mainContBelow) return
304 S.drain (runContT mainContAbove return)
306 S.drain (runExceptT mainEitherAbove)
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