.. _composing:

************************
Composing State Machines
************************

In the previous section, we defined a ``DataStore`` interface and used it
to implement the following small program which allows a user to log in to
the store then display the store's contents;

.. code-block:: idris

  getData : (ConsoleIO m, DataStore m) => ST m () []
  getData = do st <- connect
               OK <- login st
                  | BadPassword => do putStrLn "Failure"
                                      disconnect st
               secret <- readSecret st
               putStrLn ("Secret is: " ++ show secret)
               logout st
               disconnect st

This function only uses one state, the store itself. Usually, though,
larger programs have lots of states, and might add, delete and update
states over the course of its execution. Here, for example, a useful
extension might be to loop forever, keeping count of the number of times
there was a login failure in a state.

Furthermore, we may have *hierarchies* of state machines, in that one
state machine could be implemented by composing several others. For
example, we can have a state machine representing the state of a
graphics system, and use this to implement a *higher level* graphics API
such as turtle graphics, which uses the graphics system plus some additional
state for the turtle.

In this section, we'll see how to work with multiple states, and how to
compose state machines to make higher level state machines. We'll begin by
seeing how to add a login failure counter to ``getData``.

Working with multiple resources
===============================

To see how to work with multiple resources, we'll modify ``getData`` so
that it loops, and counts the total number of times the user fails to
log in. For example, if we write a ``main`` program which initialises the
count to zero, a session might run as follows:

.. code::

    *LoginCount> :exec main
    Enter password: Mornington Crescent
    Secret is: "Secret Data"
    Enter password: Dollis Hill
    Failure
    Number of failures: 1
    Enter password: Mornington Crescent
    Secret is: "Secret Data"
    Enter password: Codfanglers
    Failure
    Number of failures: 2
    ...

We'll start by adding a state resource to ``getData`` to keep track of the
number of failures:

.. code-block:: idris

  getData : (ConsoleIO m, DataStore m) =>
            (failcount : Var) -> ST m () [failcount ::: State Integer]

.. topic:: Type checking ``getData``

  If you're following along in the code, you'll find that ``getData``
  no longer compiles when you update this type. That is to be expected!
  For the moment, comment out the definition of ``getData``. We'll come back
  to it shortly.

Then, we can create a ``main`` program which initialises the state to ``0``
and invokes ``getData``, as follows:

.. code-block:: idris

  main : IO ()
  main = run (do fc <- new 0
                 getData fc
                 delete fc)

We'll start our implementation of ``getData`` just by adding the new
argument for the failure count:

.. code-block:: idris

  getData : (ConsoleIO m, DataStore m) =>
            (failcount : Var) -> ST m () [failcount ::: State Integer]
  getData failcount
          = do st <- connect
               OK <- login st
                  | BadPassword => do putStrLn "Failure"
                                      disconnect st
               secret <- readSecret st
               putStrLn ("Secret is: " ++ show secret)
               logout st
               disconnect st

Unfortunately, this doesn't type check, because we have the wrong resources
for calling ``connect``. The error messages shows how the resources don't
match:

.. code-block:: idris

    When checking an application of function Control.ST.>>=:
        Error in state transition:
                Operation has preconditions: []
                States here are: [failcount ::: State Integer]
                Operation has postconditions: \result => [result ::: Store LoggedOut] ++ []
                Required result states here are: st2_fn

In other words, ``connect`` requires that there are *no* resources on
entry, but we have *one*, the failure count!
This shouldn't be a problem, though: the required resources are a *subset* of
the resources we have, after all, and the additional resources (here, the
failure count) are not relevant to ``connect``. What we need, therefore,
is a way to temporarily *hide* the additional resource.

We can achieve this with the ``call`` function:

.. code-block:: idris

  getData : (ConsoleIO m, DataStore m) =>
            (failcount : Var) -> ST m () [failcount ::: State Integer]
  getData failcount
     = do st <- call connect
          ?whatNow

Here we've left a hole for the rest of ``getData`` so that you can see the
effect of ``call``. It has removed the unnecessary parts of the resource
list for calling ``connect``, then reinstated them on return. The type of
``whatNow`` therefore shows that we've added a new resource ``st``, and still
have ``failcount`` available:

.. code-block:: idris

      failcount : Var
      m : Type -> Type
      constraint : ConsoleIO m
      constraint1 : DataStore m
      st : Var
    --------------------------------------
    whatNow : STrans m () [failcount ::: State Integer, st ::: Store LoggedOut]
                          (\result => [failcount ::: State Integer])

By the end of the function, ``whatNow`` says that we need to have finished with
``st``, but still have ``failcount`` available. We can complete ``getData``
so that it works with an additional state resource by adding ``call`` whenever
we invoke one of the operations on the data store, to reduce the list of
resources:

.. code-block:: idris

  getData : (ConsoleIO m, DataStore m) =>
            (failcount : Var) -> ST m () [failcount ::: State Integer]
  getData failcount
          = do st <- call connect
               OK <- call $ login st
                  | BadPassword => do putStrLn "Failure"
                                      call $ disconnect st
               secret <- call $ readSecret st
               putStrLn ("Secret is: " ++ show secret)
               call $ logout st
               call $ disconnect st

This is a little noisy, and in fact we can remove the need for it by
making ``call`` implicit. By default, you need to add the ``call`` explicitly,
but if you import ``Control.ST.ImplicitCall``, Idris will insert ``call``
where it is necessary.

.. code-block:: idris

  import Control.ST.ImplicitCall

It's now possible to write ``getData`` exactly as before:

.. code-block:: idris

  getData : (ConsoleIO m, DataStore m) =>
            (failcount : Var) -> ST m () [failcount ::: State Integer]
  getData failcount
          = do st <- connect
               OK <- login st
                  | BadPassword => do putStrLn "Failure"
                                      disconnect st
               secret <- readSecret st
               putStrLn ("Secret is: " ++ show secret)
               logout st
               disconnect st

There is a trade off here: if you import ``Control.ST.ImplicitCall`` then
functions which use multiple resources are much easier to read, because the
noise of ``call`` has gone. On the other hand, Idris has to work a little
harder to type check your functions, and as a result it can take slightly
longer, and the error messages can be less helpful.

It is instructive to see the type of ``call``:

.. code-block:: idris

    call : STrans m t sub new_f -> {auto res_prf : SubRes sub old} ->
           STrans m t old (\res => updateWith (new_f res) old res_prf)

The function being called has a list of resources ``sub``, and
there is an implicit proof, ``SubRes sub old`` that the resource list in
the function being called is a subset of the overall resource list. The
ordering of resources is allowed to change, although resources which
appear in ``old`` can't appear in the ``sub`` list more than once (you will
get a type error if you try this).

The function ``updateWith`` takes the *output* resources of the
called function, and updates them in the current resource list. It makes
an effort to preserve ordering as far as possible, although this isn't
always possible if the called function does some complicated resource
manipulation.

.. topic:: Newly created resources in called functions

   If the called function creates any new resources, these will typically
   appear at the *end* of the resource list, due to the way ``updateWith``
   works. You can see this in the type of ``whatNow`` in our incomplete
   definition of ``getData`` above.

Finally, we can update ``getData`` so that it loops, and keeps
``failCount`` updated as necessary:

.. code-block:: idris

  getData : (ConsoleIO m, DataStore m) =>
            (failcount : Var) -> ST m () [failcount ::: State Integer]
  getData failcount
     = do st <- call connect
          OK <- login st
             | BadPassword => do putStrLn "Failure"
                                 fc <- read failcount
                                 write failcount (fc + 1)
                                 putStrLn ("Number of failures: " ++ show (fc + 1))
                                 disconnect st
                                 getData failcount
          secret <- readSecret st
          putStrLn ("Secret is: " ++ show secret)
          logout st
          disconnect st
          getData failcount

Note that here, we're connecting and disconnecting on every iteration.
Another way to implement this would be to ``connect`` first, then call
``getData``, and implement ``getData`` as follows:

.. code-block:: idris

  getData : (ConsoleIO m, DataStore m) =>
            (st, failcount : Var) -> ST m () [st ::: Store {m} LoggedOut, failcount ::: State Integer]
  getData st failcount
     = do OK <- login st
             | BadPassword => do putStrLn "Failure"
                                 fc <- read failcount
                                 write failcount (fc + 1)
                                 putStrLn ("Number of failures: " ++ show (fc + 1))
                                 getData st failcount
          secret <- readSecret st
          putStrLn ("Secret is: " ++ show secret)
          logout st
          getData st failcount

It is important to add the explicit ``{m}`` in the type of ``Store {m}
LoggedOut`` for ``st``, because this gives Idris enough information to know
which implementation of ``DataStore`` to use to find the appropriate
implementation for ``Store``. Otherwise, if we only write ``Store LoggedOut``,
there's no way to know that the ``Store`` is linked with the computation
context ``m``.

We can then ``connect`` and ``disconnect`` only once, in ``main``:

.. code-block:: idris

  main : IO ()
  main = run (do fc <- new 0
                 st <- connect
                 getData st fc
                 disconnect st
                 delete fc)

By using ``call``, and importing ``Control.ST.ImplicitCall``, we can
write programs which use multiple resources, and reduce the list of
resources as necessary when calling functions which only use a subset of
the overall resources.

Composite resources: Hierarchies of state machines
==================================================

We've now seen how to use multiple resources in one function, which is
necessary for any realistic program which manipulates state. We can think
of this as "horizontal" composition: using multiple resources at once.
We'll often also need "vertical" composition: implementing one resource
in terms of one or more other resources.

We'll see an example of this in this section. First, we'll implement a
small API for graphics, in an interface ``Draw``, supporting:

* Opening a window, creating a double-buffered surface to draw on
* Drawing lines and rectangles onto a surface
* "Flipping" buffers, displaying the surface we've just drawn onto in
  the window
* Closing a window

Then, we'll use this API to implement a higher level API for turtle graphics,
in an ``interface``.
This will require not only the ``Draw`` interface, but also a representation
of the turtle state (location, direction and pen colour).

.. topic:: SDL bindings

    For the examples in this section, you'll need to install the
    (very basic!) SDL bindings for Idris, available from
    https://github.com/edwinb/SDL-idris. These bindings implement a small
    subset of the SDL API, and are for illustrative purposes only.
    Nevertheless, they are enough to implement small graphical programs
    and demonstrate the concepts of this section.

    Once you've installed this package, you can start Idris with the
    ``-p sdl`` flag, for the SDL bindings, and the ``-p contrib`` flag,
    for the ``Control.ST`` library.

The ``Draw`` interface
----------------------

We're going to use the Idris SDL bindings for this API, so you'll need
to import ``Graphics.SDL`` once you've installed the bindings.
We'll start by defining the ``Draw`` interface, which includes a data type
representing a surface on which we'll draw lines and rectangles:

.. code-block:: idris

    interface Draw (m : Type -> Type) where
        Surface : Type

We'll need to be able to create a new ``Surface`` by opening a window:

.. code-block:: idris

    initWindow : Int -> Int -> ST m Var [add Surface]

However, this isn't quite right. It's possible that opening a window
will fail, for example if our program is running in a terminal without
a windowing system available. So, somehow, ``initWindow`` needs to cope
with the possibility of failure. We can do this by returning a
``Maybe Var``, rather than a ``Var``, and only adding the ``Surface``
on success:

.. code-block:: idris

    initWindow : Int -> Int -> ST m (Maybe Var) [addIfJust Surface]

This uses a type level function ``addIfJust``, defined in ``Control.ST``
which returns an ``Action`` that only adds a resource if the operation
succeeds (that is, returns a result of the form ``Just val``.

.. topic:: ``addIfJust`` and ``addIfRight``

  ``Control.ST`` defines functions for constructing new resources if an
  operation succeeds. As well as ``addIfJust``, which adds a resource if
  an operation returns ``Just ty``, there's also ``addIfRight``:

  .. code-block:: idris

     addIfJust : Type -> Action (Maybe Var)
     addIfRight : Type -> Action (Either a Var)

  Each of these is implemented in terms of the following primitive action
  ``Add``, which takes a function to construct a resource list from the result
  of an operation:

  .. code-block:: idris

     Add : (ty -> Resources) -> Action ty

  Using this, you can create your own actions to add resources
  based on the result of an operation, if required. For example,
  ``addIfJust`` is implemented as follows:

  .. code-block:: idris

     addIfJust : Type -> Action (Maybe Var)
     addIfJust ty = Add (maybe [] (\var => [var ::: ty]))

If we create windows, we'll also need to be able to delete them:

.. code-block:: idris

    closeWindow : (win : Var) -> ST m () [remove win Surface]

We'll also need to respond to events such as keypresses and mouse clicks.
The ``Graphics.SDL`` library provides an ``Event`` type for this, and
we can ``poll`` for events which returns the last event which occurred,
if any:

.. code-block:: idris

    poll : ST m (Maybe Event) []

The remaining methods of ``Draw`` are ``flip``, which flips the buffers
displaying everything that we've drawn since the previous ``flip``, and
two methods for drawing: ``filledRectangle`` and ``drawLine``.

.. code-block:: idris

    flip : (win : Var) -> ST m () [win ::: Surface]
    filledRectangle : (win : Var) -> (Int, Int) -> (Int, Int) -> Col -> ST m () [win ::: Surface]
    drawLine : (win : Var) -> (Int, Int) -> (Int, Int) -> Col -> ST m () [win ::: Surface]

We define colours as follows, as four components (red, green, blue, alpha):

.. code-block:: idris

  data Col = MkCol Int Int Int Int

  black : Col
  black = MkCol 0 0 0 255

  red : Col
  red = MkCol 255 0 0 255

  green : Col
  green = MkCol 0 255 0 255

  -- Also blue, yellow, magenta, cyan, white, similarly...

If you import ``Graphics.SDL``, you can implement the ``Draw`` interface
using the SDL bindings as follows:

.. code-block:: idris

  implementation Draw IO where
    Surface = State SDLSurface

    initWindow x y = do Just srf <- lift (startSDL x y)
                             | pure Nothing
                        var <- new srf
                        pure (Just var)

    closeWindow win = do lift endSDL
                         delete win

    flip win = do srf <- read win
                  lift (flipBuffers srf)
    poll = lift pollEvent

    filledRectangle win (x, y) (ex, ey) (MkCol r g b a)
         = do srf <- read win
              lift $ filledRect srf x y ex ey r g b a
    drawLine win (x, y) (ex, ey) (MkCol r g b a)
         = do srf <- read win
              lift $ drawLine srf x y ex ey r g b a

In this implementation, we've used ``startSDL`` to initialise a window, which,
returns ``Nothing`` if it fails. Since the type of ``initWindow`` states that
it adds a resource when it returns a value of the form ``Just val``, we
add the surface returned by ``startSDL`` on success, and nothing on
failure.  We can only successfully initialise if ``startDSL`` succeeds.

Now that we have an implementation of ``Draw``, we can try writing some
functions for drawing into a window and execute them via the SDL bindings.
For example, assuming we have a surface ``win`` to draw onto, we can write a
``render`` function as follows which draws a line onto a black background:

.. code-block:: idris

  render : Draw m => (win : Var) -> ST m () [win ::: Surface {m}]
  render win = do filledRectangle win (0,0) (640,480) black
                  drawLine win (100,100) (200,200) red
                  flip win

The ``flip win`` at the end is necessary because the drawing primitives
are double buffered, to prevent flicker. We draw onto one buffer, off-screen,
and display the other.  When we call ``flip``, it displays the off-screen
buffer, and creates a new off-screen buffer for drawing the next frame.

To include this in a program, we'll write a main loop which renders our
image and waits for an event to indicate the user wants to close the
application:

.. code-block:: idris

  loop : Draw m => (win : Var) -> ST m () [win ::: Surface {m}]
  loop win = do render win
                Just AppQuit <- poll
                     | _ => loop win
                pure ()

Finally, we can create a main program which initialises a window, if
possible, then runs the main loop:

.. code-block:: idris

  drawMain : (ConsoleIO m, Draw m) => ST m () []
  drawMain = do Just win <- initWindow 640 480
                   | Nothing => putStrLn "Can't open window"
                loop win
                closeWindow win

We can try this at the REPL using ``run``:

.. code::

  *Draw> :exec run drawMain

A higher level interface: ``TurtleGraphics``
--------------------------------------------

Turtle graphics involves a "turtle" moving around the screen, drawing a line as
it moves with a "pen". A turtle has attributes describing its location, the
direction it's facing, and the current pen colour. There are commands for
moving the turtle forwards, turning through an angle, and changing the
pen colour, among other things. One possible interface would be the
following:

.. code-block:: idris

  interface TurtleGraphics (m : Type -> Type) where
    Turtle : Type

    start : Int -> Int -> ST m (Maybe Var) [addIfJust Turtle]
    end : (t : Var) -> ST m () [Remove t Turtle]

    fd : (t : Var) -> Int -> ST m () [t ::: Turtle]
    rt : (t : Var) -> Int -> ST m () [t ::: Turtle]

    penup : (t : Var) -> ST m () [t ::: Turtle]
    pendown : (t : Var) -> ST m () [t ::: Turtle]
    col : (t : Var) -> Col -> ST m () [t ::: Turtle]

    render : (t : Var) -> ST m () [t ::: Turtle]

Like ``Draw``, we have a command for initialising the turtle (here called
``start``) which might fail if it can't create a surface for the turtle to
draw on. There is also a ``render`` method, which is intended to render the
picture drawn so far in a window.  One possible program with this interface
is the following, with draws a colourful square:

.. code-block:: idris

  turtle : (ConsoleIO m, TurtleGraphics m) => ST m () []
  turtle = with ST do
              Just t <- start 640 480
                   | Nothing => putStr "Can't make turtle\n"
              col t yellow
              fd t 100; rt t 90
              col t green
              fd t 100; rt t 90
              col t red
              fd t 100; rt t 90
              col t blue
              fd t 100; rt t 90
              render t
              end t

.. topic:: ``with ST do``

  The purpose of ``with ST do`` in ``turtle`` is to disambiguate ``(>>=)``,
  which could be either the version from the ``Monad`` interface, or the
  version from ``ST``. Idris can work this out itself, but it takes time to
  try all of the possibilities, so the ``with`` clause can
  speed up type checking.

To implement the interface, we could try using ``Surface`` to represent
the surface for the turtle to draw on:

.. code-block:: idris

    implementation Draw m => TurtleGraphics m where
      Turtle = Surface {m}

Knowing that a ``Turtle`` is represented as a ``Surface``, we can use the
methods provided by ``Draw`` to implement the turtle.  Unfortunately, though,
this isn't quite enough. We need to store more information: in particular, the
turtle has several attributes which we need to store somewhere.
So, not only do we need to represent the turtle as a ``Surface``, we need
to store some additional state. We can achieve this using a *composite*
resource.

Introducing composite resources
-------------------------------

A *composite* resource is built up from a list of other resources, and
is implemented using the following type, defined by ``Control.ST``:

.. code-block:: idris

  data Composite : List Type -> Type

If we have a composite resource, we can split it into its constituent
resources, and create new variables for each of those resources, using
the *split* function. For example:

.. code-block:: idris

  splitComp : (comp : Var) -> ST m () [comp ::: Composite [State Int, State String]]
  splitComp comp = do [int, str] <- split comp
                      ?whatNow

The call ``split comp`` extracts the ``State Int`` and ``State String`` from
the composite resource ``comp``, and stores them in the variables ``int``
and ``str`` respectively. If we check the type of ``whatNow``, we'll see
how this has affected the resource list:

.. code-block:: idris

      int : Var
      str : Var
      comp : Var
      m : Type -> Type
    --------------------------------------
    whatNow : STrans m () [int ::: State Int, str ::: State String, comp ::: State ()]
                          (\result => [comp ::: Composite [State Int, State String]])

So, we have two new resources ``int`` and ``str``, and the type of
``comp`` has been updated to the unit type, so currently holds no data.
This is to be expected: we've just extracted the data into individual
resources after all.

Now that we've extracted the individual resources, we can manipulate them
directly (say, incrementing the ``Int`` and adding a newline to the
``String``) then rebuild the composite resource using ``combine``:

.. code-block:: idris

  splitComp : (comp : Var) ->
              ST m () [comp ::: Composite [State Int, State String]]
  splitComp comp = do [int, str] <- split comp
                      update int (+ 1)
                      update str (++ "\n")
                      combine comp [int, str]
                      ?whatNow

As ever, we can check the type of ``whatNow`` to see the effect of
``combine``:

.. code-block:: idris

      comp : Var
      int : Var
      str : Var
      m : Type -> Type
    --------------------------------------
    whatNow : STrans m () [comp ::: Composite [State Int, State String]]
                     (\result => [comp ::: Composite [State Int, State String]])

The effect of ``combine``, therefore, is to take existing
resources and merge them into one composite resource. Before we run
``combine``, the target resource must exist (``comp`` here) and must be
of type ``State ()``.

It is instructive to look at the types of ``split`` and ``combine`` to see
the requirements on resource lists they work with. The type of ``split``
is the following:

.. code-block:: idris

    split : (lbl : Var) -> {auto prf : InState lbl (Composite vars) res} ->
            STrans m (VarList vars) res (\vs => mkRes vs ++ updateRes res prf (State ()))

The implicit ``prf`` argument says that the ``lbl`` being split must be
a composite resource. It returns a variable list, built from the composite
resource, and the ``mkRes`` function makes a list of resources of the
appropriate types. Finally, ``updateRes`` updates the composite resource to
have the type ``State ()``.

The ``combine`` function does the inverse:

.. code-block:: idris

    combine : (comp : Var) -> (vs : List Var) ->
              {auto prf : InState comp (State ()) res} ->
              {auto var_prf : VarsIn (comp :: vs) res} ->
              STrans m () res (const (combineVarsIn res var_prf))

The implicit ``prf`` argument here ensures that the target resource ``comp``
has type ``State ()``. That is, we're not overwriting any other data.
The implicit ``var_prf`` argument is similar to ``SubRes`` in ``call``, and
ensures that every variable we're using to build the composite resource
really does exist in the current resource list.

We can use composite resources to implement our higher level ``TurtleGraphics``
API in terms of ``Draw``, and any additional resources we need.

Implementing ``Turtle``
-----------------------

Now that we've seen how to build a new resource from an existing collection,
we can implement ``Turtle`` using a composite resource, containing the
``Surface`` to draw on, and individual states for the pen colour and the
pen location and direction. We also have a list of lines, which describes
what we'll draw onto the ``Surface`` when we call ``render``:

.. code-block:: idris

  Turtle = Composite [Surface {m}, -- surface to draw on
                      State Col,  -- pen colour
                      State (Int, Int, Int, Bool), -- pen location/direction/d
                      State (List Line)] -- lines to draw on render

A ``Line`` is defined as a start location, and end location, and a colour:

.. code-block:: idris

  Line : Type
  Line = ((Int, Int), (Int, Int), Col)

To implement ``start``, which creates a new ``Turtle`` (or returns ``Nothing``
if this is impossible), we begin by initialising the drawing surface then
all of the components of the state. Finally, we combine all of these
into a composite resource for the turtle:

.. code-block:: idris

    start x y = do Just srf <- initWindow x y
                        | Nothing => pure Nothing
                   col <- new white
                   pos <- new (320, 200, 0, True)
                   lines <- new []
                   turtle <- new ()
                   combine turtle [srf, col, pos, lines]
                   pure (Just turtle)

To implement ``end``, which needs to dispose of the turtle,
we deconstruct the composite resource, close the window,
then remove each individual resource. Remember that we can only ``delete``
a ``State``, so we need to ``split`` the composite resource, close the
drawing surface cleanly with ``closeWindow``, then ``delete`` the states:

.. code-block:: idris

    end t = do [srf, col, pos, lines] <- split t
               closeWindow srf; delete col; delete pos; delete lines; delete t

For the other methods, we need to ``split`` the resource to get each
component, and ``combine`` into a composite resource when we're done.
As an example, here's ``penup``:

.. code-block:: idris

    penup t = do [srf, col, pos, lines] <- split t -- Split the composite resource
                 (x, y, d, _) <- read pos          -- Deconstruct the pen position
                 write pos (x, y, d, False)        -- Set the pen down flag to False
                 combine t [srf, col, pos, lines]  -- Recombine the components

The remaining operations on the turtle follow a similar pattern. See
``samples/ST/Graphics/Turtle.idr`` in the Idris distribution for the full
details. It remains to render the image created by the turtle:

.. code-block:: idris

    render t = do [srf, col, pos, lines] <- split t -- Split the composite resource
                  filledRectangle srf (0, 0) (640, 480) black -- Draw a background
                  drawAll srf !(read lines)         -- Render the lines drawn by the turtle
                  flip srf                          -- Flip the buffers to display the image
                  combine t [srf, col, pos, lines]
                  Just ev <- poll
                    | Nothing => render t           -- Keep going until a key is pressed
                  case ev of
                       KeyUp _ => pure ()           -- Key pressed, so quit
                       _ => render t
     where drawAll : (srf : Var) -> List Line -> ST m () [srf ::: Surface {m}]
           drawAll srf [] = pure ()
           drawAll srf ((start, end, col) :: xs)
              = do drawLine srf start end col       -- Draw a line in the appropriate colour
                   drawAll srf xs
