packages feed

essence-of-live-coding-0.2.5: src/LiveCoding/Preliminary/CellExcept.lhs

\begin{comment}
\begin{code}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RecordWildCards #-}

module LiveCoding.Preliminary.CellExcept where

-- base
import Control.Arrow
import Data.Data
import Data.Either (fromRight)
import Data.Void

-- transformers
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Except

-- essence-of-live-coding
import LiveCoding.Cell
import LiveCoding.Preliminary.CellExcept.Applicative
import LiveCoding.Exceptions
\end{code}
\end{comment}

\paragraph{Using exceptions}
\fxwarning{We didn't mention the newtype in the last paragraph, this is maybe confusing}
We can enter the \mintinline{haskell}{CellExcept} context from an exception-throwing cell,
trying to execute it until the exception occurs:
\fxerror{This doesn't work here anymore because we haven't explained how it's a newtype.
Also we already know that try needs an extra type class. Take this from the monad section.}
\begin{code}
try
  :: Data          e
  => Cell (ExceptT e m) a b
  -> CellExcept      m  a b e
try = CellExcept id
\end{code}
And we can leave it safely once we have proven that there are no exceptions left to throw,
i.e. the exception type is empty (represented in Haskell by \mintinline{haskell}{Void}):
\fxerror{I'm using runCellExcept which wasn't explained yet}
\begin{code}
safely
  :: Monad      m
  => CellExcept m a b Void
  -> Cell       m a b
safely = hoistCell discardVoid . runCellExcept

discardVoid
  :: Functor      m
  => ExceptT Void m a
  ->              m a
discardVoid
  = fmap (either absurd id) . runExceptT
\end{code}
One way to prove the absence of further exceptions is,
of course, to run an exception-free cell:
\begin{code}
safe :: Monad m => Cell m a b -> CellExcept m a b void
safe cell = CellExcept
  { fmapExcept = absurd
  , cellExcept = liftCell cell
  }
\end{code}
If we want to leave an exception unhandled,
this is also possible:
\begin{code}
runCellExcept
  :: Monad           m
  => CellExcept      m  a b e
  -> Cell (ExceptT e m) a b
runCellExcept CellExcept { .. }
  = hoistCell (withExceptT fmapExcept)
    cellExcept
\end{code}
This is especially useful for shutting down a live program gracefully,
using \mintinline{haskell}{e} as the exit code.
\fxerror{But we haven't implemented that yet. And also can only do that with a more general "reactimate"}