turtle-1.6.2: Shell programming, Haskell-style

Safe Haskell | Safe-Inferred
Language | Haskell2010

Turtle.Shell

Contents

- Shell
- Embeddings

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 `Shell`s using the `Shell` constructor. Instead, use these functions to generate primitive `Shell`s:

- `empty`, to create a `Shell` that outputs nothing
- `return`, to create a `Shell` that outputs a single value
- `select`, to range over a list of values within a `Shell`
- `liftIO`, to embed an `IO` action within a `Shell`
- `using`, to acquire a `Managed` resource within a `Shell`

Then use these classes to combine those primitive `Shell`s into larger `Shell`s:

- `Alternative`, to concatenate `Shell` outputs using (`<|>`)
- `Monad`, to build `Shell` comprehensions using `do` notation

If you still insist on building your own `Shell` from scratch, then the `Shell` you build must satisfy this law:

    -- For every shell `s`:
    _foldShell s (FoldShell step begin done) = do
        x' <- _foldShell s (FoldShell step begin 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.

Synopsis

- newtype Shell a = Shell {
  - _foldShell :: forall r. FoldShell a r -> IO r
  }
- data FoldShell a b = FoldShell (x -> a -> IO x) x (x -> IO b)
- _foldIO :: Shell a -> FoldM IO a r -> IO r
- _Shell :: (forall r. FoldM IO a r -> IO r) -> Shell a
- foldIO :: MonadIO io => Shell a -> FoldM IO a r -> io r
- foldShell :: MonadIO io => Shell a -> FoldShell a b -> io b
- fold :: MonadIO io => Shell a -> Fold a b -> io b
- reduce :: MonadIO io => Fold a b -> Shell a -> io b
- sh :: MonadIO io => Shell a -> io ()
- view :: (MonadIO io, Show a) => Shell a -> io ()
- select :: Foldable f => f a -> Shell a
- liftIO :: MonadIO m => IO a -> m a
- using :: MonadManaged m => Managed a -> m a
- fromIO :: IO (Maybe a) -> Shell a

# Shell

newtype Shell a #

A `(Shell a)` is a protected stream of `a`'s with side effects

Constructors

Shell |

Fields

- _foldShell :: forall r. FoldShell a r -> IO r

#### Instances

Instances details

MonadIO Shell # |
Instance details Defined in Turtle.Shell Methods liftIO :: IO a -> Shell a #
MonadCatch Shell # |
Instance details Defined in Turtle.Shell Methods catch :: (HasCallStack, Exception e) => Shell a -> (e -> Shell a) -> Shell a #
MonadThrow Shell # |
Instance details Defined in Turtle.Shell Methods throwM :: (HasCallStack, Exception e) => e -> Shell a #
Alternative Shell # |
Instance details Defined in Turtle.Shell Methods empty :: Shell a # (<|>) :: Shell a -> Shell a -> Shell a # some :: Shell a -> Shell [a] # many :: Shell a -> Shell [a] #
Applicative Shell # |
Instance details Defined in Turtle.Shell Methods pure :: a -> Shell a # (<*>) :: Shell (a -> b) -> Shell a -> Shell b # liftA2 :: (a -> b -> c) -> Shell a -> Shell b -> Shell c # (*>) :: Shell a -> Shell b -> Shell b # (<*) :: Shell a -> Shell b -> Shell a #
Functor Shell # |
Instance details Defined in Turtle.Shell Methods fmap :: (a -> b) -> Shell a -> Shell b # (<$) :: a -> Shell b -> Shell a #
Monad Shell # |
Instance details Defined in Turtle.Shell Methods (>>=) :: Shell a -> (a -> Shell b) -> Shell b # (>>) :: Shell a -> Shell b -> Shell b # return :: a -> Shell a #
MonadPlus Shell # |
Instance details Defined in Turtle.Shell Methods mzero :: Shell a # mplus :: Shell a -> Shell a -> Shell a #
MonadFail Shell # |
Instance details Defined in Turtle.Shell Methods fail :: String -> Shell a #
MonadManaged Shell # |
Instance details Defined in Turtle.Shell Methods using :: Managed a -> Shell a #
Monoid a => Monoid (Shell a) # |
Instance details Defined in Turtle.Shell Methods mempty :: Shell a # mappend :: Shell a -> Shell a -> Shell a # mconcat :: [Shell a] -> Shell a #
Monoid a => Semigroup (Shell a) # |
Instance details Defined in Turtle.Shell Methods (<>) :: Shell a -> Shell a -> Shell a # sconcat :: NonEmpty (Shell a) -> Shell a # stimes :: Integral b => b -> Shell a -> Shell a #
IsString a => IsString (Shell a) # |
Instance details Defined in Turtle.Shell Methods fromString :: String -> Shell a #
Monoid a => Num (Shell a) # | Shell forms a semiring, this is the closest approximation
Instance details Defined in Turtle.Shell Methods (+) :: Shell a -> Shell a -> Shell a # (-) :: Shell a -> Shell a -> Shell a # (*) :: Shell a -> Shell a -> Shell a # negate :: Shell a -> Shell a # abs :: Shell a -> Shell a # signum :: Shell a -> Shell a # fromInteger :: Integer -> Shell a #

data FoldShell a b #

This is similar to ``FoldM` `IO`` except that the `begin` field is pure

This small difference is necessary to implement a well-behaved `MonadCatch` instance for `Shell`

Constructors

FoldShell (x -> a -> IO x) x (x -> IO b) |

_foldIO :: Shell a -> FoldM IO a r -> IO r #

Provided for backwards compatibility with versions of `turtle-1.4.*` and older

_Shell :: (forall r. FoldM IO a r -> IO r) -> Shell a #

Provided for ease of migration from versions of `turtle-1.4.*` and older

foldIO :: MonadIO io => Shell a -> FoldM IO a r -> io r #

Use a ``FoldM` `IO`` to reduce the stream of `a`'s produced by a `Shell`

foldShell :: MonadIO io => Shell a -> FoldShell a b -> io b #

Use a `FoldShell` to reduce the stream of `a`'s produced by a `Shell`

fold :: MonadIO io => Shell a -> Fold a b -> io b #

Use a `Fold` to reduce the stream of `a`'s produced by a `Shell`

reduce :: MonadIO io => Fold a b -> Shell a -> io b #

Flipped version of `fold`. Useful for reducing a stream of data

#### Example

Expand

Sum a `Shell` of numbers:

    >>> select [1, 2, 3] & reduce Fold.sum
    6

sh :: MonadIO io => Shell a -> io () #

Run a `Shell` to completion, discarding any unused values

view :: (MonadIO io, Show a) => Shell a -> io () #

Run a `Shell` to completion, `print`ing any unused values

# Embeddings

select :: Foldable f => f a -> Shell a #

Convert a list to a `Shell` that emits each element of the list

liftIO :: MonadIO m => IO a -> m a #

Lift a computation from the `IO` monad. This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations (i.e. `IO` is the base monad for the stack).

### Example

Expand

    import Control.Monad.Trans.State -- from the "transformers" library

    printState :: Show s => StateT s IO ()
    printState = do
      state <- get
      liftIO $ print state

Had we omitted ``liftIO``, we would have ended up with this error:

    • Couldn't match type ‘IO’ with ‘StateT s IO’
     Expected type: StateT s IO ()
       Actual type: IO ()

The important part here is the mismatch between `StateT s IO ()` and ``IO` ()`.

Luckily, we know of a function that takes an ``IO` a` and returns an `(m a)`: ``liftIO``, enabling us to run the program and see the expected results:

    > evalStateT printState "hello"
    "hello"

    > evalStateT printState 3
    3

using :: MonadManaged m => Managed a -> m a #

fromIO :: IO (Maybe a) -> Shell a #

Convert an `IO` action that returns a `Maybe` into a `Shell`