LogicGrowsOnTrees-1.0.0: sources/LogicGrowsOnTrees/Parallel/ExplorationMode.hs
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UnicodeSyntax #-}
{-| There are several tasks for which a user may wish to use LogicGrowsOnTrees,
such as gathering up all the results in a tree or stopping as soon as the
first result is found. Because almost all of the infrastructure required for
these different modes is the same, rather than creating a different system
for each mode we instead re-use the same system but pass around a mode
parameter that dictates its behavior at various points as well as some of
the types in the system.
'ExplorationMode' is defined using a GADT where each constructor has a
different argument for `ExplorationMode`\'s type parameter; this was
done so that type families can be used to specialized types depending on the
constructor.
-}
module LogicGrowsOnTrees.Parallel.ExplorationMode
(
-- * Types
ExplorationMode(..)
, AllMode
, FirstMode
, FoundModeUsingPull
, FoundModeUsingPush
-- * Type-classes
, HasExplorationMode(..)
-- * Type families
, ResultFor
, ProgressFor
, FinalResultFor
, WorkerIntermediateValueFor
, WorkerFinishedProgressFor
-- * Functions
, checkpointFromIntermediateProgress
, initialProgress
, initialWorkerIntermediateValue
) where
import Data.Monoid
import LogicGrowsOnTrees.Checkpoint
--------------------------------------------------------------------------------
------------------------------------ Types -------------------------------------
--------------------------------------------------------------------------------
{-| A type indicating the mode of the exploration. Note that this is a GADT for
which the type parameter is unique to each constructor in order to allow
associated types to be specialized based on the value.
Unfortunately Haddock does not seem to support documenting the constructors
of a GADT, so the documentation for each constructor is located at the type
it is tagged with, all of which are defined after the 'ExplorationMode'
type.
-}
data ExplorationMode exploration_mode where
AllMode :: Monoid result ⇒ ExplorationMode (AllMode result)
FirstMode :: ExplorationMode (FirstMode result)
FoundModeUsingPull :: Monoid result ⇒ (result → Bool) → ExplorationMode (FoundModeUsingPull result)
FoundModeUsingPush :: Monoid result ⇒ (result → Bool) → ExplorationMode (FoundModeUsingPush result)
{-| Explore the entire tree and sum the results in all of the leaves. -}
data AllMode result
{-| Explore the tree until a result is found, and if so then stop. -}
data FirstMode result
{-| Explore the tree, summing the results, until a condition has been met;
`Pull` means that each worker's results will be kept and summed locally
until a request for them has been received from the supervisor, which means
that there might be a period of time where the collectively found results
meet the condition but the system is unaware of this as they are scattered
amongst the workers.
NOTE: If you use this mode then you are responsible for ensuring that a
global progress update happens on a regular basis in order to pull
the results in from the workers and check to see if the condition has
been met; if you do not do this then the run will not terminate
until the tree has been fully explored.
-}
data FoundModeUsingPull result
{-| Same as 'FoundModeUsingPull', but pushes each result to the supervisor as it
is found rather than summing them in the worker until they are requested by
the supervisor, which guarantees that the system will recognize when the
condition has been met as soon as final result needed was found but has the
downside that if there are a large number of results needed then sending
each one could be much more costly then summing them locally and sending the
current total on a regular basis to the supervisor.
-}
data FoundModeUsingPush result
--------------------------------------------------------------------------------
--------------------------------- Type-classes ---------------------------------
--------------------------------------------------------------------------------
{-| This class indicates that a monad has information about the current
exploration mode tag type that can be extracted from it.
-}
class HasExplorationMode (monad :: * → *) where
type ExplorationModeFor monad :: *
--------------------------------------------------------------------------------
-------------------------------- Type families ---------------------------------
--------------------------------------------------------------------------------
{- $families
The type families in this section allow the types to be used at various places
to be specialized based on the current exploration mode.
-}
{-| The result type of the tree, i.e. the type of values at the leaves. -}
type family ResultFor exploration_mode :: *
type instance ResultFor (AllMode result) = result
type instance ResultFor (FirstMode result) = result
type instance ResultFor (FoundModeUsingPull result) = result
type instance ResultFor (FoundModeUsingPush result) = result
{-| The type of progress, which keeps track of how much of the tree has already
been explored.
-}
type family ProgressFor exploration_mode :: *
type instance ProgressFor (AllMode result) = Progress result
type instance ProgressFor (FirstMode result) = Checkpoint
type instance ProgressFor (FoundModeUsingPull result) = Progress result
type instance ProgressFor (FoundModeUsingPush result) = Progress result
{-| The type of the final result of exploring the tree. -}
type family FinalResultFor exploration_mode :: *
type instance FinalResultFor (AllMode result) = result
type instance FinalResultFor (FirstMode result) = Maybe (Progress result)
type instance FinalResultFor (FoundModeUsingPull result) = Either result (Progress result)
type instance FinalResultFor (FoundModeUsingPush result) = Either result (Progress result)
{-| The type of the intermediate value being maintained internally by the worker. -}
type family WorkerIntermediateValueFor exploration_mode :: *
type instance WorkerIntermediateValueFor (AllMode result) = result
type instance WorkerIntermediateValueFor (FirstMode result) = ()
type instance WorkerIntermediateValueFor (FoundModeUsingPull result) = result
type instance WorkerIntermediateValueFor (FoundModeUsingPush result) = ()
{-| The progress type returned by a worker that has finished. -}
type family WorkerFinishedProgressFor exploration_mode :: *
type instance WorkerFinishedProgressFor (AllMode result) = Progress result
type instance WorkerFinishedProgressFor (FirstMode result) = Progress (Maybe result)
type instance WorkerFinishedProgressFor (FoundModeUsingPull result) = Progress result
type instance WorkerFinishedProgressFor (FoundModeUsingPush result) = Progress result
--------------------------------------------------------------------------------
---------------------------------- Functions -----------------------------------
--------------------------------------------------------------------------------
{-| Extracts the 'Checkpoint' component from a progress value. -}
checkpointFromIntermediateProgress ::
ExplorationMode exploration_mode →
ProgressFor exploration_mode →
Checkpoint
checkpointFromIntermediateProgress AllMode = progressCheckpoint
checkpointFromIntermediateProgress FirstMode = id
checkpointFromIntermediateProgress (FoundModeUsingPull _) = progressCheckpoint
checkpointFromIntermediateProgress (FoundModeUsingPush _) = progressCheckpoint
{-| The initial progress at the start of the exploration. -}
initialProgress :: ExplorationMode exploration_mode → ProgressFor exploration_mode
initialProgress AllMode = mempty
initialProgress FirstMode = mempty
initialProgress (FoundModeUsingPull _) = mempty
initialProgress (FoundModeUsingPush _) = mempty
{-| The initial intermediate value for the worker. -}
initialWorkerIntermediateValue ::
ExplorationMode exploration_mode →
WorkerIntermediateValueFor exploration_mode
initialWorkerIntermediateValue AllMode = mempty
initialWorkerIntermediateValue FirstMode = ()
initialWorkerIntermediateValue (FoundModeUsingPull _) = mempty
initialWorkerIntermediateValue (FoundModeUsingPush _) = ()