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 , MonadIO (t (MaybeT m))
45getSequenceMaybeBelow = do
46 liftIO $ putStrLn "MaybeT below streamly: Enter one char per line: "
48 i <- S.fromFoldable [1..2 :: Int]
49 liftIO $ putStrLn $ "iteration = " <> show i
52 when (r1 /= "x") $ lift mzero
55 when (r2 /= "y") $ lift mzero
57mainMaybeBelow :: IO ()
59 r <- runMaybeT (S.drain getSequenceMaybeBelow)
61 Just _ -> putStrLn "Bingo"
62 Nothing -> putStrLn "Wrong"
64-------------------------------------------------------------------------------
65-- Using MaybeT above streamly
66-------------------------------------------------------------------------------
68-- When MaybeT is on top a Nothing would terminate only the current iteration
69-- of non-determinism below.
71-- Note that this is redundant configuration as the same behavior can be
72-- achieved with just streamly, using mzero.
74getSequenceMaybeAbove :: (IsStream t, MonadIO (t m)) => MaybeT (t m) ()
75getSequenceMaybeAbove = do
76 liftIO $ putStrLn "MaybeT above streamly: Enter one char per line: "
78 i <- lift $ S.fromFoldable [1..2 :: Int]
79 liftIO $ putStrLn $ "iteration = " <> show i
82 when (r1 /= "x") mzero
85 when (r2 /= "y") mzero
87mainMaybeAbove :: (IsStream t, MonadIO (t m)) => MaybeT (t m) ()
90 liftIO $ putStrLn "Bingo"
92-------------------------------------------------------------------------------
93-- Using ExceptT below streamly
94-------------------------------------------------------------------------------
96-- XXX need to have a specialized liftCatch to lift catchE
98-- Note that throwE would terminate all iterations of non-determinism
100getSequenceEitherBelow
104 , MonadIO (t (ExceptT String m))
106 => t (ExceptT String m) ()
107getSequenceEitherBelow = do
108 liftIO $ putStrLn "ExceptT below streamly: Enter one char per line: "
110 i <- S.fromFoldable [1..2 :: Int]
111 liftIO $ putStrLn $ "iteration = " <> show i
114 when (r1 /= "x") $ lift $ throwE $ "Expecting x got: " <> r1
117 when (r2 /= "y") $ lift $ throwE $ "Expecting y got: " <> r2
119mainEitherBelow :: IO ()
121 -- XXX Cannot lift catchE
122 r <- runExceptT (S.drain getSequenceEitherBelow)
124 Right _ -> liftIO $ putStrLn "Bingo"
125 Left s -> liftIO $ putStrLn s
127-------------------------------------------------------------------------------
128-- Using ExceptT below concurrent streamly
129-------------------------------------------------------------------------------
131-- XXX does not work correctly yet
133getSequenceEitherAsyncBelow
137 , MonadIO (t (ExceptT String m))
138 , Semigroup (t (ExceptT String m) Integer)
140 => t (ExceptT String m) ()
141getSequenceEitherAsyncBelow = do
142 liftIO $ putStrLn "ExceptT below concurrent streamly: "
144 i <- (liftIO (threadDelay 1000)
145 >> lift (throwE "First task")
147 <> (lift (throwE "Second task") >> return 2)
148 <> S.yield (3 :: Integer)
149 liftIO $ putStrLn $ "iteration = " <> show i
151mainEitherAsyncBelow :: IO ()
152mainEitherAsyncBelow = do
153 r <- runExceptT (S.drain $ asyncly getSequenceEitherAsyncBelow)
155 Right _ -> liftIO $ putStrLn "Bingo"
156 Left s -> liftIO $ putStrLn s
158-------------------------------------------------------------------------------
159-- Using ExceptT above streamly
160-------------------------------------------------------------------------------
162-- When ExceptT is on top, we can lift the non-determinism of stream from
165-- Note that throwE would terminate/break only current iteration of
166-- non-determinism and not all of them altogether.
168-- Here we can use catchE directly but will have to use monad-control to lift
169-- stream operations with stream arguments.
170getSequenceEitherAbove :: (IsStream t, MonadIO (t m))
171 => ExceptT String (t m) ()
172getSequenceEitherAbove = do
173 liftIO $ putStrLn "ExceptT above streamly: Enter one char per line: "
175 i <- lift $ S.fromFoldable [1..2 :: Int]
176 liftIO $ putStrLn $ "iteration = " <> show i
179 when (r1 /= "x") $ throwE $ "Expecting x got: " <> r1
182 when (r2 /= "y") $ throwE $ "Expecting y got: " <> r2
184mainEitherAbove :: (IsStream t, MonadIO (t m)) => ExceptT String (t m) ()
186 catchE (getSequenceEitherAbove >> liftIO (putStrLn "Bingo"))
189-------------------------------------------------------------------------------
190-- Using MonadThrow to throw exceptions in streamly
191-------------------------------------------------------------------------------
193newtype Unexpected = Unexpected String deriving Show
195instance Exception Unexpected
197-- Note that unlike when ExceptT is used on top, MonadThrow terminates all
198-- iterations of non-determinism rather then just the current iteration.
200getSequenceMonadThrow :: (IsStream t, MonadIO (t m), MonadThrow (t m))
202getSequenceMonadThrow = do
203 liftIO $ putStrLn "MonadThrow in streamly: Enter one char per line: "
205 i <- S.fromFoldable [1..2 :: Int]
206 liftIO $ putStrLn $ "iteration = " <> show i
209 when (r1 /= "x") $ throwM $ Unexpected $ "Expecting x got: " <> r1
212 when (r2 /= "y") $ throwM $ Unexpected $ "Expecting y got: " <> r2
214mainMonadThrow :: IO ()
216 catch (S.drain getSequenceMonadThrow >> liftIO (putStrLn "Bingo"))
217 (\(e :: SomeException) -> liftIO $ print e)
219-------------------------------------------------------------------------------
220-- Using ContT below streamly
221-------------------------------------------------------------------------------
223-- CallCC is the goto/setjmp/longjmp equivalent
224-- Allows us to manipulate the control flow in arbitrary ways
226-- XXX need to have a specialized liftCallCC to actually lift callCC
229 :: (IsStream t, MonadTrans t, MonadIO m, MonadIO (t (ContT r m)))
230 => t (ContT r m) (Either String ())
231getSequenceContBelow = do
232 liftIO $ putStrLn "ContT below streamly: Enter one char per line: "
234 i <- S.fromFoldable [1..2 :: Int]
235 liftIO $ putStrLn $ "iteration = " <> show i
237 r <- lift $ callCC $ \exit -> do
240 then exit $ Left $ "Expecting x got: " <> r1
241 else return $ Right ()
245 then exit $ Left $ "Expecting y got: " <> r2
246 else return $ Right ()
247 liftIO $ putStrLn $ "done iteration = " <> show i
251 :: (IsStream t, MonadIO m, MonadTrans t, MonadIO (t (ContT r m)))
254 r <- getSequenceContBelow
256 Right _ -> liftIO $ putStrLn "Bingo"
257 Left s -> liftIO $ putStrLn s
259-------------------------------------------------------------------------------
260-- Using ContT above streamly
261-------------------------------------------------------------------------------
263getSequenceContAbove :: (IsStream t, MonadIO (t m))
264 => ContT r (t m) (Either String ())
265getSequenceContAbove = do
266 liftIO $ putStrLn "ContT above streamly: Enter one char per line: "
268 i <- lift $ S.fromFoldable [1..2 :: Int]
269 liftIO $ putStrLn $ "iteration = " <> show i
274 then exit $ Left $ "Expecting x got: " <> r1
275 else return $ Right ()
279 then exit $ Left $ "Expecting y got: " <> r2
280 else return $ Right ()
282mainContAbove :: (IsStream t, MonadIO (t m)) => ContT r (t m) ()
284 r <- getSequenceContAbove
286 Right _ -> liftIO $ putStrLn "Bingo"
287 Left s -> liftIO $ putStrLn s
289-------------------------------------------------------------------------------
290-- Combining control flow manipulating monad transformers (MaybeT, exceptT,
291-- ContT) with Streamly
292-------------------------------------------------------------------------------
297 S.drain $ runMaybeT mainMaybeAbove
298 runContT (S.drain mainContBelow) return
299 S.drain (runContT mainContAbove return)
301 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