Introducing App
===============

``App`` is declared as below, in a module ``Control.App``, which is part of
the ``base`` libraries.
It is parameterised by an implicit
``Path`` (which states whether the program's execution path
is linear or might throw
exceptions), which has a ``default`` value that the program
might throw, and a ``List Error``
(which gives a list of exception types which can be thrown, ``Error`` is
a synonym for ``Type``):

.. code-block:: idris

    data App : {default MayThrow l : Path} ->
               (es : List Error) -> Type -> Type

It serves the same purpose as ``IO``, but supports throwing and catching
exceptions, and allows us to define more constrained interfaces parameterised
by the list of errors ``es``.
e.g. a program which supports console IO:

.. code-block:: idris

    hello : Console es => App es ()
    hello = putStrLn "Hello, App world!"

We can use this in a complete program as follows:

.. code-block:: idris

    module Main

    import Control.App
    import Control.App.Console

    hello : Console es => App es ()
    hello = putStrLn "Hello, App world!"

    main : IO ()
    main = run hello

Or, a program which supports console IO and carries an ``Int`` state,
labelled ``Counter``:

.. code-block:: idris

    data Counter : Type where

    helloCount : (Console es, State Counter Int es) => App es ()
    helloCount = do c <- get Counter
                    put Counter (c + 1)
                    putStrLn "Hello, counting world"
                    c <- get Counter
                    putStrLn ("Counter " ++ show c)

To run this as part of a complete program, we need to initialise the state.

.. code-block:: idris

    main : IO ()
    main = run (new 93 helloCount)

For convenience, we can list multiple interfaces in one go, using a function
``Has``, defined in ``Control.App``, to compute the interface constraints:

.. code-block:: idris

    helloCount : Has [Console, State Counter Int] es => App es ()

    0 Has : List (a -> Type) -> a -> Type
    Has [] es = ()
    Has (e :: es') es = (e es, Has es' es)

The purpose of ``Path`` is to state whether a program can throw
exceptions, so that we can know where it is safe to reference linear
resources. It is declared as follows:

.. code-block:: idris

    data Path = MayThrow | NoThrow

The type of ``App`` states that ``MayThrow`` is the default.
We expect this to be the most
common case. After all, realistically, most operations have possible failure
modes, especially those which interact with the outside world.

The ``0`` on the declaration of ``Has`` indicates that it can only
be run in an erased context, so it will never be run at run-time.
To run an ``App`` inside ``IO``, we use an initial
list of errors ``Init`` (recall that an ``Error`` is a
synonym for ``Type``):

.. code-block:: idris

    Init : List Error
    Init = [AppHasIO]

    run : App {l} Init a -> IO a

Generalising the ``Path`` parameter with ``l``
means that we can invoke ``run`` for any application, whether the ``Path``
is ``NoThrow`` or ``MayThrow``. But, in practice, all applications
given to ``run`` will not throw at the top level, because the only
exception type available is the type ``AppHasIO``. Any exceptions
will have been introduced and handled inside the ``App``.
