\begin{comment}
\begin{code}
{-# LANGUAGE Arrows #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
module LiveCoding.Bind where
import Control.Arrow
import Control.Concurrent (threadDelay)
import Data.Data
import Data.Either (fromRight)
import Data.Void
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except
import Control.Monad.Trans.Reader
import LiveCoding.Cell
import LiveCoding.CellExcept
import LiveCoding.Exceptions
import LiveCoding.LiveProgram
\end{code}
\end{comment}
\begin{comment}
%After this long excursion,
We can finally return to the example.
Let us again change the period of the oscillator,
only this time not manually,
but at the moment the position reaches 0:
\begin{code}
throwWhen0
:: Monad m
=> Cell (ExceptT () m) Double Double
throwWhen0 :: Cell (ExceptT () m) Double Double
throwWhen0 = proc Double
pos ->
if Double
pos Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
0
then Cell (ExceptT () m) () Double
forall (m :: * -> *) e arbitrary.
Monad m =>
Cell (ExceptT e m) e arbitrary
throwC -< ()
else Cell (ExceptT () m) Double Double
forall (a :: * -> * -> *) b. Arrow a => a b b
returnA -< Double
pos
sineChangeE :: CellExcept () Double IO Void
sineChangeE = do
Cell (ExceptT () IO) () Double -> CellExcept () Double IO ()
forall e (m :: * -> *) a b.
(Data e, Finite e) =>
Cell (ExceptT e m) a b -> CellExcept a b m e
try (Cell (ExceptT () IO) () Double -> CellExcept () Double IO ())
-> Cell (ExceptT () IO) () Double -> CellExcept () Double IO ()
forall a b. (a -> b) -> a -> b
$ Double -> Cell (ExceptT () IO) () Double
forall (m :: * -> *). MonadFix m => Double -> Cell m () Double
sine Double
6 Cell (ExceptT () IO) () Double
-> Cell (ExceptT () IO) Double Double
-> Cell (ExceptT () IO) () Double
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Cell (ExceptT () IO) Double Double
forall (m :: * -> *). Monad m => Cell (ExceptT () m) Double Double
throwWhen0
Cell (ExceptT () IO) () Double -> CellExcept () Double IO ()
forall e (m :: * -> *) a b.
(Data e, Finite e) =>
Cell (ExceptT e m) a b -> CellExcept a b m e
try (Cell (ExceptT () IO) () Double -> CellExcept () Double IO ())
-> Cell (ExceptT () IO) () Double -> CellExcept () Double IO ()
forall a b. (a -> b) -> a -> b
$ (ExceptT () IO () -> Cell (ExceptT () IO) () ()
forall (m :: * -> *) b a. m b -> Cell m a b
constM (ExceptT () IO () -> Cell (ExceptT () IO) () ())
-> ExceptT () IO () -> Cell (ExceptT () IO) () ()
forall a b. (a -> b) -> a -> b
$ IO () -> ExceptT () IO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> ExceptT () IO ()) -> IO () -> ExceptT () IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
putStrLn String
"I changed!")
Cell (ExceptT () IO) () ()
-> Cell (ExceptT () IO) () Double -> Cell (ExceptT () IO) () Double
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Cell (ExceptT () IO) () Double
forall (m :: * -> *) e arbitrary.
Monad m =>
Cell (ExceptT e m) e arbitrary
throwC
Cell IO () Double -> CellExcept () Double IO Void
forall (m :: * -> *) a b.
Monad m =>
Cell m a b -> CellExcept a b m Void
safe (Cell IO () Double -> CellExcept () Double IO Void)
-> Cell IO () Double -> CellExcept () Double IO Void
forall a b. (a -> b) -> a -> b
$ Double -> Cell IO () Double
forall (m :: * -> *). MonadFix m => Double -> Cell m () Double
sine Double
10
\end{code}
\end{comment}
\begin{code}
sineWait
:: Double -> CellExcept () String IO Void
sineWait :: Double -> CellExcept () String IO Void
sineWait Double
t = do
Cell (ExceptT () IO) () String -> CellExcept () String IO ()
forall e (m :: * -> *) a b.
(Data e, Finite e) =>
Cell (ExceptT e m) a b -> CellExcept a b m e
try (Cell (ExceptT () IO) () String -> CellExcept () String IO ())
-> Cell (ExceptT () IO) () String -> CellExcept () String IO ()
forall a b. (a -> b) -> a -> b
$ (() -> String) -> Cell (ExceptT () IO) () String
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr (String -> () -> String
forall a b. a -> b -> a
const String
"Waiting...") Cell (ExceptT () IO) () String
-> Cell (ExceptT () IO) String String
-> Cell (ExceptT () IO) () String
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Double -> Cell (ExceptT () IO) String String
forall (m :: * -> *) a.
Monad m =>
Double -> Cell (ExceptT () m) a a
wait Double
2
Cell IO () String -> CellExcept () String IO Void
forall (m :: * -> *) a b.
Monad m =>
Cell m a b -> CellExcept a b m Void
safe (Cell IO () String -> CellExcept () String IO Void)
-> Cell IO () String -> CellExcept () String IO Void
forall a b. (a -> b) -> a -> b
$ Double -> Cell IO () Double
forall (m :: * -> *). MonadFix m => Double -> Cell m () Double
sine Double
t Cell IO () Double -> Cell IO Double String -> Cell IO () String
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> (Double -> String) -> Cell IO Double String
forall (a :: * -> * -> *) b c. Arrow a => (b -> c) -> a b c
arr Double -> String
asciiArt
\end{code}
This \mintinline{haskell}{do}-block can be read intuitively.
Initially, the first cell is executed,
which returns the message \mintinline{haskell}{"Waiting..."} every second.
After three seconds, it throws an exception,
which is handled by activating the sine generator.
Since all exceptions have been handled,
we leave the \mintinline{haskell}{CellExcept} context and run the resulting program:
\begin{code}
printSineWait :: LiveProgram IO
printSineWait :: LiveProgram IO
printSineWait = Cell IO () () -> LiveProgram IO
forall (m :: * -> *). Monad m => Cell m () () -> LiveProgram m
liveCell
(Cell IO () () -> LiveProgram IO)
-> Cell IO () () -> LiveProgram IO
forall a b. (a -> b) -> a -> b
$ CellExcept () String IO Void -> Cell IO () String
forall (m :: * -> *) a b.
Monad m =>
CellExcept a b m Void -> Cell m a b
safely (Double -> CellExcept () String IO Void
sineWait Double
8)
Cell IO () String -> Cell IO String () -> Cell IO () ()
forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Cell IO String ()
printEverySecond
\end{code}
\verbatiminput{../demos/DemoSineWait.txt}
The crucial advantage of handling control flow this way
is that the \emph{control state}
is encoded completely in the overall state of the live program,
and can thus be migrated automatically.
Let us rerun the above example,
but after the first \mintinline{haskell}{try} statement has already passed control to the sine generator
we shorten the period length of the sine wave and reload:
\verbatiminput{../demos/DemoSineWaitChange.txt}
The migrated program did not restart and wait again,
but remembered to immediately continue executing the sine generator from the same phase as before.
This is in contrast to simplistic approaches to live coding in which the control flow state is forgotten upon reload,
and restarted each time.
In most other programming languages where control flow is builtin,
this would typically require reworking the compiler or interpreter,
but in Haskell, we succeed entirely within the language.