\begin{comment}
\begin{code}
{-# LANGUAGE Arrows #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeOperators #-}
module LiveCoding.Exceptions.Finite where
import Control.Arrow
import GHC.Generics
import Data.Data
import Data.Void
import Control.Monad.Trans.Except
import Control.Monad.Trans.Reader
import LiveCoding.Cell
import LiveCoding.Exceptions (runReaderC')
\end{code}
\end{comment}
\begin{code}
class Finite e where
commute :: Monad m => (e -> Cell m a b) -> Cell (ReaderT e m) a b
default commute :: (Generic e, GFinite (Rep e), Monad m) => (e -> Cell m a b) -> Cell (ReaderT e m) a b
commute handler = hoistCell (withReaderT from) $ gcommute $ handler . to
class GFinite f where
gcommute :: Monad m => (f e -> Cell m a b) -> Cell (ReaderT (f e) m) a b
instance GFinite f => GFinite (M1 a b f) where
gcommute handler = hoistCell (withReaderT unM1) $ gcommute $ handler . M1
instance Finite e => GFinite (K1 a e) where
gcommute handler = hoistCell (withReaderT unK1) $ commute $ handler . K1
instance GFinite V1 where
gcommute _ = error "gcommute: Can't commute with an empty type"
instance Finite Void where
commute _ = error "Nope"
instance GFinite U1 where
gcommute handler = liftCell $ handler U1
instance Finite () where
instance Finite Bool where
commute handler = proc a -> do
bool <- constM ask -< ()
if bool
then liftCell $ handler True -< a
else liftCell $ handler False -< a
instance (GFinite eL, GFinite eR) => GFinite (eL :+: eR) where
gcommute handler
= let
cellLeft = runReaderC' $ gcommute $ handler . L1
cellRight = runReaderC' $ gcommute $ handler . R1
gdistribute (L1 eR) a = Left (eR, a)
gdistribute (R1 eL) a = Right (eL, a)
in
proc a -> do
either12 <- constM ask -< ()
liftCell (cellLeft ||| cellRight) -< gdistribute either12 a
instance (Finite e1, Finite e2) => Finite (Either e1 e2) where
instance (GFinite e1, GFinite e2) => GFinite (e1 :*: e2) where
gcommute handler = hoistCell guncurryReader $ gcommute $ gcommute . gcurry handler
where
gcurry f e1 e2 = f (e1 :*: e2)
guncurryReader a = ReaderT $ \(r1 :*: r2) -> runReaderT (runReaderT a r1) r2
\end{code}