Safe Haskell | None |
---|---|
Language | Haskell2010 |
Control.Monad.Action
Description
Monoid actions, and the update monad, as well as an mtl
-style capability
type class.
A note on functional dependencies
To ensure easy inference, we make use of functional dependencies (either
directly or by an equivalent mechanism on associated type families) on both
the Action
and MonadUpdate
type classes. Specifically, we insist that:
- Any monoidal action determines the state it acts on; and
- Any particular stack that implements
MonadUpdate
determines what its action is.
This means that any given action can act on _exactly_ one state, and that any
given stack has at most one state we can act upon. The second restriction
above is in line with the other similar mtl
-style capability type classes
(such as MonadReader
, MonadState
etc), while the first is a reasonable
choice given that we want to have both good inference and also the ability
for different actions to act on the same state. Given that actions are likely
to be fairly application-specific, we don't see this as a significant
limitation.
Synopsis
- class Monoid a => Action a where
- data Actionable a
- actionable :: a -> Actionable a
- newtype UpdateT act (m :: Type -> Type) a = UpdateT (StateOf act -> m (act, a))
- runUpdateT :: forall act m a. (Functor m, Action act) => UpdateT act m a -> StateOf act -> m (StateOf act, act, a)
- class (Action act, Monad m) => MonadUpdate act (m :: Type -> Type) | m -> act where
Monoid actions
Class
class Monoid a => Action a where Source #
Describes (left) monoidal actions on a
set. In this case, the type
StateOf a
is 'the state being acted on' (or 'the state'), while a
is
'the thing doing the acting' (or 'the action').
Laws
Briefly, any instance of
defines a monoid
homomorphism
between Action
aa
and
(which is essentially Endo
(StateOf a)StateOf a ->
StateOf a)
. In Haskell terms, this means the following laws must hold:
Since: 1.0.0
Wrapper
data Actionable a Source #
Often, we want to take a type that doesn't (naturally) form a Monoid
and
use it as an action. This can be done using a range of 'free monoid
constructions', including lists. However, these aren't optimal due to the
append-heavy (and concatenation-heavy) workloads we typically need from
actions.
Actionable
is such a 'free monoid construction' which 'promotes' any
a
into a Semigroup
and a Monoid
. It is fairly opaque, providing only
the instances we really need, but it's designed for efficient appending and
concatenation.
To use Actionable
, you want to do something like this:
data MyState = ... data MyType = ... newtype MyAction = MyAction (Actionable MyType) deriving (Semigroup, Monoid) via (Actionable MyType) instance Action MyAction where type StateOf MyAction = MyState act (MyAction acts) = foldMap go acts where go :: MyType -> Endo MyState go x = Endo $ oldState -> ...
To 'inject' your type into an Actionable
, use actionable
.
Since: 1.0.0
Instances
actionable :: a -> Actionable a Source #
Wrap a value into an Actionable
.
Since: 1.0.0
Action monad
Transformer
newtype UpdateT act (m :: Type -> Type) a Source #
A transformer implementing the 'update monad' pattern, as described here.
We leave the state implicit, as it is uniquely determined by the act
type,
together with the Action
type class requirement.
Important note
This implementation is not suitable for any m
that throws exceptions. This
includes IO
, ST
and anything stacked atop them. For the reasons why, see
here.
Since: 1.0.0
Instances
(Action act, Monad m) => MonadUpdate act (UpdateT act m) Source # | Since: 1.0.0 |
Action act => MonadTrans (UpdateT act) Source # | Since: 1.0.0 |
Defined in Control.Monad.Action | |
(Action act, Monad m) => Applicative (UpdateT act m) Source # | Since: 1.0.0 |
Defined in Control.Monad.Action Methods pure :: a -> UpdateT act m a # (<*>) :: UpdateT act m (a -> b) -> UpdateT act m a -> UpdateT act m b # liftA2 :: (a -> b -> c) -> UpdateT act m a -> UpdateT act m b -> UpdateT act m c # (*>) :: UpdateT act m a -> UpdateT act m b -> UpdateT act m b # (<*) :: UpdateT act m a -> UpdateT act m b -> UpdateT act m a # | |
Functor m => Functor (UpdateT act m) Source # | Since: 1.0.0 |
(Action act, Monad m) => Monad (UpdateT act m) Source # | Since: 1.0.0 |
runUpdateT :: forall act m a. (Functor m, Action act) => UpdateT act m a -> StateOf act -> m (StateOf act, act, a) Source #
As runUpdate
, except that it produces the results in the 'inner monad'
of UpdateT
.
Since: 1.0.0
Capability type class
class (Action act, Monad m) => MonadUpdate act (m :: Type -> Type) | m -> act where Source #
An mtl
-style capability type class describing update monads in general,
irrespective of their states and/or actions.
Laws
If you define update
or request
, ensure the following also hold:
Laws 4 and 5 form the default definitions of update
and request
respectively, which obey all these laws.
Since: 1.0.0
Minimal complete definition
Methods
send :: act -> m (StateOf act) Source #
Performs the given action on the state, returning the result.
Since: 1.0.0
update :: act -> m () Source #
Performs the given action, returning nothing.
Since: 1.0.0
request :: m (StateOf act) Source #
Retrieves the state without doing anything to it.
Since: 1.0.0
Instances
MonadUpdate act m => MonadUpdate act (MaybeT m) Source # | Since: 1.0.0 |
(Action act, Monad m) => MonadUpdate act (UpdateT act m) Source # | Since: 1.0.0 |
MonadUpdate act m => MonadUpdate act (ExceptT e m) Source # | Since: 1.0.0 |
MonadUpdate act m => MonadUpdate act (ReaderT r m) Source # | Since: 1.0.0 |
MonadUpdate act m => MonadUpdate act (StateT s m) Source # | Since: 1.0.0 |
MonadUpdate act m => MonadUpdate act (WriterT w m) Source # | Since: 1.0.0 |
MonadUpdate act m => MonadUpdate act (RWST r w s m) Source # | Since: 1.0.0 |