{-# LANGUAGE GADTSyntax, ExistentialQuantification, Rank2Types, ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances, MultiParamTypeClasses, FlexibleInstances #-}
module Control.Monad.Operational (
Program, singleton, ProgramView, view,
interpretWithMonad,
ProgramT, ProgramViewT(..), viewT,
liftProgram, mapInstr,
unviewT, interpretWithMonadT,
) where
import Control.Monad
import Control.Monad.Identity (Identity, runIdentity)
import Control.Monad.Trans (MonadTrans, lift)
import Control.Monad.IO.Class
import Control.Monad.Reader.Class
import Control.Monad.State.Class
type Program instr = ProgramT instr Identity
type ProgramView instr = ProgramViewT instr Identity
view :: Program instr a -> ProgramView instr a
view :: forall (instr :: * -> *) a. Program instr a -> ProgramView instr a
view = forall a. Identity a -> a
runIdentity forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
ProgramT instr m a -> m (ProgramViewT instr m a)
viewT
interpretWithMonad :: forall instr m b.
Monad m => (forall a. instr a -> m a) -> (Program instr b -> m b)
interpretWithMonad :: forall (instr :: * -> *) (m :: * -> *) b.
Monad m =>
(forall a. instr a -> m a) -> Program instr b -> m b
interpretWithMonad forall a. instr a -> m a
f = forall a. ProgramView instr a -> m a
eval forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (instr :: * -> *) a. Program instr a -> ProgramView instr a
view
where
eval :: forall a. ProgramView instr a -> m a
eval :: forall a. ProgramView instr a -> m a
eval (Return a
a) = forall (m :: * -> *) a. Monad m => a -> m a
return a
a
eval (instr b
m :>>= b -> ProgramT instr Identity a
k) = forall a. instr a -> m a
f instr b
m forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (instr :: * -> *) (m :: * -> *) b.
Monad m =>
(forall a. instr a -> m a) -> Program instr b -> m b
interpretWithMonad forall a. instr a -> m a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT instr Identity a
k
data ProgramT instr m a where
Lift :: m a -> ProgramT instr m a
Bind :: ProgramT instr m b -> (b -> ProgramT instr m a)
-> ProgramT instr m a
Instr :: instr a -> ProgramT instr m a
instance Monad m => Monad (ProgramT instr m) where
return :: forall a. a -> ProgramT instr m a
return = forall (m :: * -> *) a (instr :: * -> *). m a -> ProgramT instr m a
Lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => a -> m a
return
>>= :: forall a b.
ProgramT instr m a
-> (a -> ProgramT instr m b) -> ProgramT instr m b
(>>=) = forall (instr :: * -> *) (m :: * -> *) b a.
ProgramT instr m b
-> (b -> ProgramT instr m a) -> ProgramT instr m a
Bind
instance MonadTrans (ProgramT instr) where
lift :: forall (m :: * -> *) a. Monad m => m a -> ProgramT instr m a
lift = forall (m :: * -> *) a (instr :: * -> *). m a -> ProgramT instr m a
Lift
instance Monad m => Functor (ProgramT instr m) where
fmap :: forall a b. (a -> b) -> ProgramT instr m a -> ProgramT instr m b
fmap = forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM
instance Monad m => Applicative (ProgramT instr m) where
pure :: forall a. a -> ProgramT instr m a
pure = forall (m :: * -> *) a. Monad m => a -> m a
return
<*> :: forall a b.
ProgramT instr m (a -> b)
-> ProgramT instr m a -> ProgramT instr m b
(<*>) = forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap
singleton :: instr a -> ProgramT instr m a
singleton :: forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
singleton = forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
Instr
data ProgramViewT instr m a where
Return :: a -> ProgramViewT instr m a
(:>>=) :: instr b
-> (b -> ProgramT instr m a)
-> ProgramViewT instr m a
instance Monad m => Functor (ProgramViewT instr m) where
fmap :: forall a b.
(a -> b) -> ProgramViewT instr m a -> ProgramViewT instr m b
fmap a -> b
f (Return a
a) = forall a (instr :: * -> *) (m :: * -> *).
a -> ProgramViewT instr m a
Return forall a b. (a -> b) -> a -> b
$ a -> b
f a
a
fmap a -> b
f (instr b
instr :>>= b -> ProgramT instr m a
cont) = instr b
instr forall (instr :: * -> *) b (m :: * -> *) a.
instr b -> (b -> ProgramT instr m a) -> ProgramViewT instr m a
:>>= (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT instr m a
cont)
instance Monad m => Applicative (ProgramViewT instr m) where
pure :: forall a. a -> ProgramViewT instr m a
pure = forall (m :: * -> *) a. Monad m => a -> m a
return
<*> :: forall a b.
ProgramViewT instr m (a -> b)
-> ProgramViewT instr m a -> ProgramViewT instr m b
(<*>) = forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap
instance Monad m => Monad (ProgramViewT instr m) where
return :: forall a. a -> ProgramViewT instr m a
return = forall a (instr :: * -> *) (m :: * -> *).
a -> ProgramViewT instr m a
Return
Return a
a >>= :: forall a b.
ProgramViewT instr m a
-> (a -> ProgramViewT instr m b) -> ProgramViewT instr m b
>>= a -> ProgramViewT instr m b
cont = a -> ProgramViewT instr m b
cont a
a
(instr b
instr :>>= b -> ProgramT instr m a
cont1) >>= a -> ProgramViewT instr m b
cont2 = instr b
instr forall (instr :: * -> *) b (m :: * -> *) a.
instr b -> (b -> ProgramT instr m a) -> ProgramViewT instr m a
:>>= (b -> ProgramT instr m a
cont1 forall (m :: * -> *) a b c.
Monad m =>
(a -> m b) -> (b -> m c) -> a -> m c
>=> forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
ProgramViewT instr m a -> ProgramT instr m a
unviewT forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ProgramViewT instr m b
cont2)
viewT :: Monad m => ProgramT instr m a -> m (ProgramViewT instr m a)
viewT :: forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
ProgramT instr m a -> m (ProgramViewT instr m a)
viewT (Lift m a
m) = m a
m forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a (instr :: * -> *) (m :: * -> *).
a -> ProgramViewT instr m a
Return
viewT ((Lift m b
m) `Bind` b -> ProgramT instr m a
g) = m b
m forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
ProgramT instr m a -> m (ProgramViewT instr m a)
viewT forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT instr m a
g
viewT ((ProgramT instr m b
m `Bind` b -> ProgramT instr m b
g) `Bind` b -> ProgramT instr m a
h) = forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
ProgramT instr m a -> m (ProgramViewT instr m a)
viewT (ProgramT instr m b
m forall (instr :: * -> *) (m :: * -> *) b a.
ProgramT instr m b
-> (b -> ProgramT instr m a) -> ProgramT instr m a
`Bind` (\b
x -> b -> ProgramT instr m b
g b
x forall (instr :: * -> *) (m :: * -> *) b a.
ProgramT instr m b
-> (b -> ProgramT instr m a) -> ProgramT instr m a
`Bind` b -> ProgramT instr m a
h))
viewT ((Instr instr b
i) `Bind` b -> ProgramT instr m a
g) = forall (m :: * -> *) a. Monad m => a -> m a
return (instr b
i forall (instr :: * -> *) b (m :: * -> *) a.
instr b -> (b -> ProgramT instr m a) -> ProgramViewT instr m a
:>>= b -> ProgramT instr m a
g)
viewT (Instr instr a
i) = forall (m :: * -> *) a. Monad m => a -> m a
return (instr a
i forall (instr :: * -> *) b (m :: * -> *) a.
instr b -> (b -> ProgramT instr m a) -> ProgramViewT instr m a
:>>= forall (m :: * -> *) a. Monad m => a -> m a
return)
liftProgram :: Monad m => Program instr a -> ProgramT instr m a
liftProgram :: forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
Program instr a -> ProgramT instr m a
liftProgram (Lift Identity a
m) = forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. Identity a -> a
runIdentity Identity a
m)
liftProgram (ProgramT instr Identity b
m `Bind` b -> ProgramT instr Identity a
k) = forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
Program instr a -> ProgramT instr m a
liftProgram ProgramT instr Identity b
m forall (instr :: * -> *) (m :: * -> *) b a.
ProgramT instr m b
-> (b -> ProgramT instr m a) -> ProgramT instr m a
`Bind` (forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
Program instr a -> ProgramT instr m a
liftProgram forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT instr Identity a
k)
liftProgram (Instr instr a
i) = forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
Instr instr a
i
interpretWithMonadT :: Monad m => (forall x . instr x -> m x) -> ProgramT instr m a -> m a
interpretWithMonadT :: forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
(forall x. instr x -> m x) -> ProgramT instr m a -> m a
interpretWithMonadT forall x. instr x -> m x
interpreter = forall {b}. ProgramT instr m b -> m b
go
where
go :: ProgramT instr m b -> m b
go ProgramT instr m b
program = do
ProgramViewT instr m b
firstInstruction <- forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
ProgramT instr m a -> m (ProgramViewT instr m a)
viewT ProgramT instr m b
program
case ProgramViewT instr m b
firstInstruction of
Return b
a -> forall (m :: * -> *) a. Monad m => a -> m a
return b
a
instr b
instruction :>>= b -> ProgramT instr m b
continuation -> forall x. instr x -> m x
interpreter instr b
instruction forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (ProgramT instr m b -> m b
go forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT instr m b
continuation)
unviewT :: Monad m => ProgramViewT instr m a -> ProgramT instr m a
unviewT :: forall (m :: * -> *) (instr :: * -> *) a.
Monad m =>
ProgramViewT instr m a -> ProgramT instr m a
unviewT (Return a
a) = forall (m :: * -> *) a. Monad m => a -> m a
return a
a
unviewT (instr b
instruction :>>= b -> ProgramT instr m a
continuation) =
(forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
Instr instr b
instruction) forall (instr :: * -> *) (m :: * -> *) b a.
ProgramT instr m b
-> (b -> ProgramT instr m a) -> ProgramT instr m a
`Bind` b -> ProgramT instr m a
continuation
mapInstr ::
forall instr1 instr2 m a . Monad m
=> (forall x . instr1 x -> instr2 x)
-> ProgramT instr1 m a -> ProgramT instr2 m a
mapInstr :: forall (instr1 :: * -> *) (instr2 :: * -> *) (m :: * -> *) a.
Monad m =>
(forall x. instr1 x -> instr2 x)
-> ProgramT instr1 m a -> ProgramT instr2 m a
mapInstr forall x. instr1 x -> instr2 x
f = forall x. ProgramT instr1 m x -> ProgramT instr2 m x
go
where
go :: forall x. ProgramT instr1 m x -> ProgramT instr2 m x
go :: forall x. ProgramT instr1 m x -> ProgramT instr2 m x
go (Lift m x
action) = forall (m :: * -> *) a (instr :: * -> *). m a -> ProgramT instr m a
Lift m x
action
go (Bind ProgramT instr1 m b
action b -> ProgramT instr1 m x
continuation) = forall (instr :: * -> *) (m :: * -> *) b a.
ProgramT instr m b
-> (b -> ProgramT instr m a) -> ProgramT instr m a
Bind (forall x. ProgramT instr1 m x -> ProgramT instr2 m x
go ProgramT instr1 m b
action) (forall x. ProgramT instr1 m x -> ProgramT instr2 m x
go forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT instr1 m x
continuation)
go (Instr instr1 x
instruction) = forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
Instr forall a b. (a -> b) -> a -> b
$ forall x. instr1 x -> instr2 x
f instr1 x
instruction
instance (MonadState s m) => MonadState s (ProgramT instr m) where
get :: ProgramT instr m s
get = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall s (m :: * -> *). MonadState s m => m s
get
put :: s -> ProgramT instr m ()
put = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *). MonadState s m => s -> m ()
put
instance (MonadIO m) => MonadIO (ProgramT instr m) where
liftIO :: forall a. IO a -> ProgramT instr m a
liftIO = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
instance (MonadReader r m) => MonadReader r (ProgramT instr m) where
ask :: ProgramT instr m r
ask = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall r (m :: * -> *). MonadReader r m => m r
ask
local :: forall a. (r -> r) -> ProgramT instr m a -> ProgramT instr m a
local r -> r
r (Lift m a
m) = forall (m :: * -> *) a (instr :: * -> *). m a -> ProgramT instr m a
Lift (forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local r -> r
r m a
m)
local r -> r
r (ProgramT instr m b
m `Bind` b -> ProgramT instr m a
k) = forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local r -> r
r ProgramT instr m b
m forall (instr :: * -> *) (m :: * -> *) b a.
ProgramT instr m b
-> (b -> ProgramT instr m a) -> ProgramT instr m a
`Bind` (forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local r -> r
r forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> ProgramT instr m a
k)
local r -> r
_ (Instr instr a
i) = forall (instr :: * -> *) a (m :: * -> *).
instr a -> ProgramT instr m a
Instr instr a
i