| CARVIEW |
early: Early return syntax in do-notation (GHC plugin)
Modules
- Control
- Control.Early
- Data
- Data.Early
- EarlyPlugin
Downloads
- early-0.0.0.tar.gz [browse] (Cabal source package)
- Package description (as included in the package)
Maintainer's Corner
For package maintainers and hackage trustees
Candidates
- No Candidates
| Versions [RSS] | 0.0.0 |
|---|---|
| Dependencies | base (>=4.7 && <5), containers, ghc, ghc-lib-parser, syb, text, transformers, unordered-containers [details] |
| License | BSD-3-Clause |
| Copyright | 2021 Chris Done |
| Author | Sky Above Limited |
| Maintainer | chris@skyabove.io |
| Uploaded | by ChrisDone at 2021-01-06T10:29:35Z |
| Category | Development |
| Home page | https://github.com/inflex-io/early#readme |
| Bug tracker | https://github.com/inflex-io/early/issues |
| Source repo | head: git clone https://github.com/inflex-io/early |
| Distributions | |
| Executables | early |
| Downloads | 245 total (4 in the last 30 days) |
| Rating | (no votes yet) [estimated by Bayesian average] |
| Your Rating |
|
| Status | Docs not available [build log] All reported builds failed as of 2021-01-06 [all 3 reports] |
Readme for early-0.0.0
[back to package description]early
Add early return to any do-expression
Table of Contents
Description
This package is a GHC plugin to add special syntax for early return in
do-notation. It provides a way to terminate the current
do-expression with a result, usually a failure result, but not
necessarily. It should not be confused with an exception handler. It
uses regular values everywhere.
How it works
The plugin is enabled in any module via a pragma.
{-# OPTIONS -F -pgmF=early #-}
The syntax ? can be added to the end of any do statement to make
it short-circuit when the action produces a certain "stop" result
(such as Left, or Nothing; the particular type is type-class
based, see the Details section below).
Suppose that grabEnv :: String -> IO (Either Error String), then you
can write this:
app :: IO (Either Error String)
app = do
path <- grabEnv "PATH"?
putStrLn "Look ma, no lifts!"
magic <- grabEnv "MAGIC"?
pure (Right (path ++ magic))
Note the final pure in the do should wrap the type, as the type of
the whole do-block has changed.
That's it! See test/Main.hs for full example.
Details
The syntax stmt? is desugared in this way:
do stmt?; nextbecomesdo earlyThen stmt nextdo pat <- stmt?; next; next2becomesdo early stmt (\pat -> do next; next2; ...)
The early and earlyThen are driven by the Early class, which any
functor-like data type can implement.
early :: (Monad m, Early f) => m (f a) -> (a -> m (f b)) -> m (f b)
earlyThen :: (Monad m, Early f) => m (f a) -> m (f b) -> m (f b)
class Functor f => Early f where
dispatch :: Applicative m => f a -> (a -> m (f b)) -> m (f b)
Two provided instances out of the box are Either e and Maybe, but
others can be added freely, such as a Failure e a type of your
library, etc.
Why not ExceptT or exceptions?
Full explanation here: my recoverable errors post.
Because ExceptT (or ContT) cannot be an
instance of MonadUnliftIO. It is not unliftable; this means that
exceptions, cleanup and concurrency don't have an interpretation. This
is an area where monad transformers in mtl/transformers don't
compose. Other free monads commute, but then you have to use a free
monad which has a complicated story regarding performance.
Inspiration
The syntax and concept of using simple return values for early
termination and failure handling is inspired
by Rust's error handling. The
Early class resembles the
Try trait, but is
slightly different, as Haskell has higher-kinded types.
Additionally, one can take a Rust-like view of error handling in Haskell:
| Use-case | Haskell | Rust |
|---|---|---|
| Unrecoverable errors | Throwing exceptions | Panics |
| Recoverable errors | Return Either/Maybe |
Return Result/Some |
This plugin allows one to structure their code in such a way.
Future Work
A small library of short-circuiting traverse/fold would let one
use actions that return Either/Maybe.
Special thanks
The following people's work helped me a lot to get my work done faster:
- Shayne Fletcher and Neil Mitchell https://github.com/digital-asset/ghc-lib
- Oleg Grenrus https://github.com/phadej/idioms-plugins
- Mark Karpov https://github.com/mrkkrp/ghc-syntax-highlighter