2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE ScopedTypeVariables #-}
5-------------------------------------------------------------------------------
6-- Combining control flow manipulating monad transformers (MaybeT, exceptT,
8-------------------------------------------------------------------------------
10-- Streamly streams are non-determinism (nested looping) monads. We can use a
11-- control flow monad on top or streamly on top depending on whether we want to
12-- superimpose control flow manipulation on top of non-deterministic
13-- composition or vice-versa.
15-- This file provides an example where we enter a sequence of characters "x",
16-- and "y" on separate lines, on the command line. When any other sequence is
17-- entered the control flow short circuits at the first non-matching char and
21#if !(MIN_VERSION_base(4,11,0))
22import Data.Semigroup (Semigroup(..))
24import Control.Concurrent (threadDelay)
25import Control.Exception (catch, SomeException)
27import Control.Monad.Catch (MonadThrow, throwM, Exception)
28import Control.Monad.IO.Class
29import Control.Monad.Trans.Class
30import Control.Monad.Trans.Maybe
31import Control.Monad.Trans.Except
32import Control.Monad.Trans.Cont
33import Streamly.Prelude
34import qualified Streamly.Prelude as S
36-------------------------------------------------------------------------------
37-- Using MaybeT below streamly
38-------------------------------------------------------------------------------
40-- When streamly is on top MaybeT would terminate all iterations of
47 , MonadIO (t (MaybeT m))
50getSequenceMaybeBelow = do
51 liftIO $ putStrLn "MaybeT below streamly: Enter one char per line: "
53 i <- S.fromFoldable [1..2 :: Int]
54 liftIO $ putStrLn $ "iteration = " <> show i
57 when (r1 /= "x") $ lift mzero
60 when (r2 /= "y") $ lift mzero
62mainMaybeBelow :: IO ()
64 r <- runMaybeT (S.drain getSequenceMaybeBelow)
66 Just _ -> putStrLn "Bingo"
67 Nothing -> putStrLn "Wrong"
69-------------------------------------------------------------------------------
70-- Using MaybeT above streamly
71-------------------------------------------------------------------------------
73-- When MaybeT is on top a Nothing would terminate only the current iteration
74-- of non-determinism below.
76-- Note that this is redundant configuration as the same behavior can be
77-- achieved with just streamly, using mzero.
79getSequenceMaybeAbove :: (IsStream t, MonadIO (t m)) => MaybeT (t m) ()
80getSequenceMaybeAbove = do
81 liftIO $ putStrLn "MaybeT above streamly: Enter one char per line: "
83 i <- lift $ S.fromFoldable [1..2 :: Int]
84 liftIO $ putStrLn $ "iteration = " <> show i
87 when (r1 /= "x") mzero
90 when (r2 /= "y") mzero
92mainMaybeAbove :: (IsStream t, MonadIO (t m)) => MaybeT (t m) ()
95 liftIO $ putStrLn "Bingo"
97-------------------------------------------------------------------------------
98-- Using ExceptT below streamly
99-------------------------------------------------------------------------------
101-- XXX need to have a specialized liftCatch to lift catchE
103-- Note that throwE would terminate all iterations of non-determinism
105getSequenceEitherBelow
109 , MonadIO (t (ExceptT String m))
111 => t (ExceptT String m) ()
112getSequenceEitherBelow = do
113 liftIO $ putStrLn "ExceptT below streamly: Enter one char per line: "
115 i <- S.fromFoldable [1..2 :: Int]
116 liftIO $ putStrLn $ "iteration = " <> show i
119 when (r1 /= "x") $ lift $ throwE $ "Expecting x got: " <> r1
122 when (r2 /= "y") $ lift $ throwE $ "Expecting y got: " <> r2
124mainEitherBelow :: IO ()
126 -- XXX Cannot lift catchE
127 r <- runExceptT (S.drain getSequenceEitherBelow)
129 Right _ -> liftIO $ putStrLn "Bingo"
130 Left s -> liftIO $ putStrLn s
132-------------------------------------------------------------------------------
133-- Using ExceptT below concurrent streamly
134-------------------------------------------------------------------------------
136-- XXX does not work correctly yet
138getSequenceEitherAsyncBelow
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 (S.drain $ 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, 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, MonadIO (t m)) => 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, 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, 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, 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