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 Streamly.Prelude ((|:))
30import qualified Streamly.Prelude as S
32-------------------------------------------------------------------------------
33-- Using MaybeT below streamly
34-------------------------------------------------------------------------------
36-- When streamly is on top MaybeT would terminate all iterations of
43 , Applicative (t (MaybeT m))
44 , MonadIO (t (MaybeT m))
47getSequenceMaybeBelow = do
48 liftIO $ putStrLn "MaybeT below streamly: Enter one char per line: "
50 i <- S.fromFoldable [1..2 :: Int]
51 liftIO $ putStrLn $ "iteration = " <> show i
54 when (r1 /= "x") $ lift mzero
57 when (r2 /= "y") $ lift mzero
59mainMaybeBelow :: IO ()
61 r <- runMaybeT (runStream getSequenceMaybeBelow)
63 Just _ -> putStrLn "Bingo"
64 Nothing -> putStrLn "Wrong"
66-------------------------------------------------------------------------------
67-- Using MaybeT above streamly
68-------------------------------------------------------------------------------
70-- When MaybeT is on top a Nothing would terminate only the current iteration
71-- of non-determinism below.
73-- Note that this is redundant configuration as the same behavior can be
74-- acheived with just streamly, using mzero.
76getSequenceMaybeAbove :: (IsStream t, MonadIO (t m)) => MaybeT (t m) ()
77getSequenceMaybeAbove = do
78 liftIO $ putStrLn "MaybeT above streamly: Enter one char per line: "
80 i <- lift $ S.fromFoldable [1..2 :: Int]
81 liftIO $ putStrLn $ "iteration = " <> show i
84 when (r1 /= "x") mzero
87 when (r2 /= "y") mzero
89mainMaybeAbove :: (IsStream t, MonadIO (t m)) => MaybeT (t m) ()
92 liftIO $ putStrLn "Bingo"
94-------------------------------------------------------------------------------
95-- Using ExceptT below streamly
96-------------------------------------------------------------------------------
98-- XXX need to have a specialized liftCatch to lift catchE
100-- Note that throwE would terminate all iterations of non-determinism
102getSequenceEitherBelow
107 , MonadIO (t (ExceptT String m))
109 => t (ExceptT String m) ()
110getSequenceEitherBelow = do
111 liftIO $ putStrLn "ExceptT below streamly: Enter one char per line: "
113 i <- S.fromFoldable [1..2 :: Int]
114 liftIO $ putStrLn $ "iteration = " <> show i
117 when (r1 /= "x") $ lift $ throwE $ "Expecting x got: " <> r1
120 when (r2 /= "y") $ lift $ throwE $ "Expecting y got: " <> r2
122mainEitherBelow :: IO ()
124 -- XXX Cannot lift catchE
125 r <- runExceptT (runStream getSequenceEitherBelow)
127 Right _ -> liftIO $ putStrLn "Bingo"
128 Left s -> liftIO $ putStrLn s
130-------------------------------------------------------------------------------
131-- Using ExceptT below concurrent streamly
132-------------------------------------------------------------------------------
134-- XXX does not work correctly yet
136getSequenceEitherAsyncBelow
142 , MonadIO (t (ExceptT String m))
143 , Semigroup (t (ExceptT String m) Integer)
145 => t (ExceptT String m) ()
146getSequenceEitherAsyncBelow = do
147 liftIO $ putStrLn "ExceptT below concurrent streamly: "
149 i <- (liftIO (threadDelay 1000)
150 >> lift (throwE "First task")
152 <> (lift (throwE "Second task") >> return 2)
153 <> S.yield (3 :: Integer)
154 liftIO $ putStrLn $ "iteration = " <> show i
156mainEitherAsyncBelow :: IO ()
157mainEitherAsyncBelow = do
158 r <- runExceptT (runStream $ asyncly getSequenceEitherAsyncBelow)
160 Right _ -> liftIO $ putStrLn "Bingo"
161 Left s -> liftIO $ putStrLn s
163-------------------------------------------------------------------------------
164-- Using ExceptT above streamly
165-------------------------------------------------------------------------------
167-- When ExceptT is on top, we can lift the non-determinism of stream from
170-- Note that throwE would terminate/break only current iteration of
171-- non-determinism and not all of them altogether.
173-- Here we can use catchE directly but will have to use monad-control to lift
174-- stream operations with stream arguments.
175getSequenceEitherAbove :: (IsStream t, Monad m, MonadIO (t m))
176 => ExceptT String (t m) ()
177getSequenceEitherAbove = do
178 liftIO $ putStrLn "ExceptT above streamly: Enter one char per line: "
180 i <- lift $ S.fromFoldable [1..2 :: Int]
181 liftIO $ putStrLn $ "iteration = " <> show i
184 when (r1 /= "x") $ throwE $ "Expecting x got: " <> r1
187 when (r2 /= "y") $ throwE $ "Expecting y got: " <> r2
189mainEitherAbove :: (IsStream t, Monad m, MonadIO (t m))
190 => ExceptT String (t m) ()
192 catchE (getSequenceEitherAbove >> liftIO (putStrLn "Bingo"))
195-------------------------------------------------------------------------------
196-- Using MonadThrow to throw exceptions in streamly
197-------------------------------------------------------------------------------
199newtype Unexpected = Unexpected String deriving Show
201instance Exception Unexpected
203-- Note that unlike when ExceptT is used on top, MonadThrow terminates all
204-- iterations of non-determinism rather then just the current iteration.
206getSequenceMonadThrow :: (IsStream t, Monad m, MonadIO (t m), MonadThrow (t m))
208getSequenceMonadThrow = do
209 liftIO $ putStrLn "MonadThrow in streamly: Enter one char per line: "
211 i <- S.fromFoldable [1..2 :: Int]
212 liftIO $ putStrLn $ "iteration = " <> show i
215 when (r1 /= "x") $ throwM $ Unexpected $ "Expecting x got: " <> r1
218 when (r2 /= "y") $ throwM $ Unexpected $ "Expecting y got: " <> r2
220mainMonadThrow :: IO ()
222 catch (runStream getSequenceMonadThrow >> liftIO (putStrLn "Bingo"))
223 (\(e :: SomeException) -> liftIO $ print e)
225-------------------------------------------------------------------------------
226-- Using ContT below streamly
227-------------------------------------------------------------------------------
229-- CallCC is the goto/setjmp/longjmp equivalent
230-- Allows us to manipulate the control flow in arbitrary ways
232-- XXX need to have a specialized liftCallCC to actually lift callCC
235 :: (IsStream t, MonadTrans t, MonadIO m, MonadIO (t (ContT r m)))
236 => t (ContT r m) (Either String ())
237getSequenceContBelow = do
238 liftIO $ putStrLn "ContT below streamly: Enter one char per line: "
240 i <- S.fromFoldable [1..2 :: Int]
241 liftIO $ putStrLn $ "iteration = " <> show i
243 r <- lift $ callCC $ \exit -> do
246 then exit $ Left $ "Expecting x got: " <> r1
247 else return $ Right ()
251 then exit $ Left $ "Expecting y got: " <> r2
252 else return $ Right ()
253 liftIO $ putStrLn $ "done iteration = " <> show i
257 :: (IsStream t, MonadIO m, MonadTrans t, MonadIO (t (ContT r m)))
260 r <- getSequenceContBelow
262 Right _ -> liftIO $ putStrLn "Bingo"
263 Left s -> liftIO $ putStrLn s
265-------------------------------------------------------------------------------
266-- Using ContT above streamly
267-------------------------------------------------------------------------------
269getSequenceContAbove :: (IsStream t, Monad m, MonadIO (t m))
270 => ContT r (t m) (Either String ())
271getSequenceContAbove = do
272 liftIO $ putStrLn "ContT above streamly: Enter one char per line: "
274 i <- lift $ S.fromFoldable [1..2 :: Int]
275 liftIO $ putStrLn $ "iteration = " <> show i
280 then exit $ Left $ "Expecting x got: " <> r1
281 else return $ Right ()
285 then exit $ Left $ "Expecting y got: " <> r2
286 else return $ Right ()
288mainContAbove :: (IsStream t, Monad m, MonadIO (t m)) => ContT r (t m) ()
290 r <- getSequenceContAbove
292 Right _ -> liftIO $ putStrLn "Bingo"
293 Left s -> liftIO $ putStrLn s
295-------------------------------------------------------------------------------
296-- Combining control flow manipulating monad transformers (MaybeT, exceptT,
297-- ContT) with Streamly
298-------------------------------------------------------------------------------
303 runStream $ runMaybeT mainMaybeAbove
304 runContT (runStream mainContBelow) return
305 runStream (runContT mainContAbove return)
307 runStream (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