This is useful for modeling any calculations that are allowed.
For example, let's say that you are dealing with STM and have the following functions:
-- A database of Ints stored in a TVar
intDatabase :: TVar (ComplexDatabaseStructure Int)
-- Inserts an Int in the int database.
insertInt :: Int -> STM ()
-- Organizes the DB so that it is more efficient
optimizeDb :: STM ()
-- Checks whether an Int is in the DB
lookupInt :: Int -> STM Bool
Now optimization is nice to do after inserts, but this is not critical. So you can see this usage:
insert2AndCheck1 a b c =
insertInt a *> insertInt b *> optional optimizeDb *> lookupInt c
ints, , (- STM, , - - ), ; .
optional STM, monad Control.Monad.Error ; , .