| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
Turtle.Shell
Contents
Description
You can think of Shell as [] + IO + Managed. In fact, you can embed
all three of them within a Shell:
select :: [a] -> Shell a liftIO :: IO a -> Shell a using :: Managed a -> Shell a
Those three embeddings obey these laws:
do { x <- select m; select (f x) } = select (do { x <- m; f x })
do { x <- liftIO m; liftIO (f x) } = liftIO (do { x <- m; f x })
do { x <- with m; using (f x) } = using (do { x <- m; f x })
select (return x) = return x
liftIO (return x) = return x
using (return x) = return x... and select obeys these additional laws:
select xs <|> select ys = select (xs <|> ys) select empty = empty
You typically won't build Shells using the Shell constructor. Instead,
use these functions to generate primitive Shells:
empty, to create aShellthat outputs nothingreturn, to create aShellthat outputs a single valueselect, to range over a list of values within aShellliftIO, to embed anIOaction within aShellusing, to acquire aManagedresource within aShell
Then use these classes to combine those primitive
Shells into largerShells:Alternative, to concatenateShelloutputs using (<|>)Monad, to buildShellcomprehensions usingdonotation
If you still insist on building your own
Shellfrom scratch, then theShellyou build must satisfy this law:
-- For every shell `s`:
foldIO s (FoldM step begin done) = do
x <- step
x' <- foldIO s (FoldM step (return x) return)
done x'... which is a fancy way of saying that your Shell must call 'begin'
exactly once when it begins and call 'done' exactly once when it ends.
Shell
A (Shell a) is a protected stream of a's with side effects