Safe Haskell | None |
---|---|
Language | Haskell2010 |
A monad for working with game trees.
Synopsis
- class (Functor go, Applicative go, Monad go) => MonadGo go where
- getCursor :: go Cursor
- getCoordState :: Coord -> go CoordState
- goUp :: go Bool
- goDown :: Int -> go Bool
- goLeft :: go Bool
- goRight :: go Bool
- goToRoot :: go ()
- goToGameInfoNode :: Bool -> go Bool
- pushPosition :: go ()
- popPosition :: go (Either PopPositionError ())
- dropPosition :: go (Either DropPositionError ())
- getProperties :: go [Property]
- modifyProperties :: ([Property] -> [Property]) -> go ()
- getProperty :: Descriptor d => d -> go (Maybe Property)
- getPropertyValue :: ValuedDescriptor v d => d -> go (Maybe v)
- putProperty :: Property -> go ()
- deleteProperty :: Descriptor d => d -> go ()
- modifyProperty :: Descriptor d => d -> (Maybe Property -> Maybe Property) -> go (Either ModifyPropertyError ())
- modifyPropertyValue :: ValuedDescriptor v d => d -> (Maybe v -> Maybe v) -> go ()
- modifyPropertyString :: (Stringlike s, ValuedDescriptor s d) => d -> (String -> String) -> go ()
- modifyPropertyList :: ValuedDescriptor [v] d => d -> ([v] -> [v]) -> go ()
- modifyPropertyCoords :: ValuedDescriptor CoordList d => d -> ([Coord] -> [Coord]) -> go ()
- modifyGameInfo :: (GameInfo -> GameInfo) -> go (Either ModifyGameInfoError (GameInfo, GameInfo))
- modifyVariationMode :: (VariationMode -> VariationMode) -> go ()
- getAssignedStone :: Coord -> go (Maybe (Maybe Color))
- getAllAssignedStones :: go (Map Coord (Maybe Color))
- modifyAssignedStones :: [Coord] -> (Maybe (Maybe Color) -> Maybe (Maybe Color)) -> go ()
- getMark :: Coord -> go (Maybe Mark)
- modifyMark :: (Maybe Mark -> Maybe Mark) -> Coord -> go ()
- addChild :: Node -> go ()
- addChildAt :: Int -> Node -> go ()
- deleteChildAt :: Int -> go (Either NodeDeleteError ())
- on :: Event go h -> h -> go ()
- on0 :: Event go h -> go () -> go ()
- data GoT m a
- type GoM = GoT Identity
- runGoT :: Monad m => GoT m a -> Cursor -> m (a, Cursor)
- runGo :: GoM a -> Cursor -> (a, Cursor)
- evalGoT :: Monad m => GoT m a -> Cursor -> m a
- evalGo :: GoM a -> Cursor -> a
- execGoT :: Monad m => GoT m a -> Cursor -> m Cursor
- execGo :: GoM a -> Cursor -> Cursor
- data Step
- data GoError
- data NavigationError = NavigationCouldNotMove
- data PopPositionError
- data DropPositionError = DropPositionStackEmpty
- data ModifyPropertyError = ModifyPropertyCannotChangeType String String
- data ModifyGameInfoError = ModifyGameInfoCannotModifyRootInfo GameInfo GameInfo
- data NodeDeleteError
- goUpOrThrow :: (MonadGo m, MonadError GoError m) => m ()
- goDownOrThrow :: (MonadGo m, MonadError GoError m) => Int -> m ()
- goLeftOrThrow :: (MonadGo m, MonadError GoError m) => m ()
- goRightOrThrow :: (MonadGo m, MonadError GoError m) => m ()
- popPositionOrThrow :: (MonadGo m, MonadError GoError m) => m ()
- dropPositionOrThrow :: (MonadGo m, MonadError GoError m) => m ()
- modifyPropertyOrThrow :: (MonadGo m, MonadError GoError m, Descriptor d) => d -> (Maybe Property -> Maybe Property) -> m ()
- modifyGameInfoOrThrow :: (MonadGo m, MonadError GoError m) => (GameInfo -> GameInfo) -> m (GameInfo, GameInfo)
- deleteChildAtOrThrow :: (MonadGo m, MonadError GoError m) => Int -> m ()
- data Event go h
- data AnyEvent go = forall h. AnyEvent (Event go h)
- eventName :: Event go h -> String
- fire :: Monad m => Event (GoT m) h -> (h -> GoT m ()) -> GoT m ()
- eventHandlerFromAction :: Event go h -> go () -> h
- childAddedEvent :: Event go (ChildAddedHandler go)
- type ChildAddedHandler go = Int -> go ()
- childDeletedEvent :: Event go (ChildDeletedHandler go)
- type ChildDeletedHandler go = Cursor -> go ()
- gameInfoChangedEvent :: Event go (GameInfoChangedHandler go)
- type GameInfoChangedHandler go = GameInfo -> GameInfo -> go ()
- navigationEvent :: Event go (NavigationHandler go)
- type NavigationHandler go = Step -> go ()
- propertiesModifiedEvent :: Event go (PropertiesModifiedHandler go)
- type PropertiesModifiedHandler go = [Property] -> [Property] -> go ()
- variationModeChangedEvent :: Event go (VariationModeChangedHandler go)
- type VariationModeChangedHandler go = VariationMode -> VariationMode -> go ()
The Go monad
class (Functor go, Applicative go, Monad go) => MonadGo go where Source #
A monad (transformer) for navigating and mutating Cursor
s, and
remembering previous locations. See GoT
and GoM
.
The monad supports handlers for events raised during actions it takes, such as navigating through the tree and modifying nodes.
getCursor, goUp, goDown, goLeft, goRight, goToRoot, goToGameInfoNode, pushPosition, popPosition, dropPosition, modifyProperties, getProperty, modifyProperty, modifyGameInfo, modifyVariationMode, addChildAt, deleteChildAt, on
getCursor :: go Cursor Source #
Returns the current cursor.
getCoordState :: Coord -> go CoordState Source #
Returns the CoordState
at the given point.
Navigates up to the parent node, fires a navigationEvent
, then returns
true. If already at the root of the tree, then none of this happens and
false is returned.
goDown :: Int -> go Bool Source #
Navigates down the tree to the child with the given index, fires a
navigationEvent
, then returns true. If the requested child doesn't
exist, then none of this happens and false is returned.
If possible, moves to the sibling node immediately to the left of the
current one. Returns whether a move was made (i.e. whether there was a
left sibling). Fires navigationEvent
s while moving.
If possible, moves to the sibling node immediately to the right of the
current one. Returns whether a move was made (i.e. whether there was a
right sibling). Fires navigationEvent
s while moving.
Navigates up to the root of the tree. Fires navigationEvent
s for each
step.
:: Bool | When no node with game info is found, then if false, return to the original node, otherwise finish at the root node. |
-> go Bool |
Navigates up the tree to the node containing game info properties, if any. Returns true if a game info node was found.
pushPosition :: go () Source #
Pushes the current location in the game tree onto an internal position
stack, such that popPosition
is capable of navigating back to the same
position, even if the game tree has been modified (though the old position
must still exist in the tree to return to it).
popPosition :: go (Either PopPositionError ()) Source #
Returns to the last position pushed onto the internal position stack via
pushPosition
, if there is one. Returns a code indicating the result of
the action.
dropPosition :: go (Either DropPositionError ()) Source #
Drops the last position pushed onto the internal stack by pushPosition
off of the stack, if there is one. Returns a code indicating the result of
the action.
getProperties :: go [Property] Source #
Returns the set of properties on the current node.
modifyProperties :: ([Property] -> [Property]) -> go () Source #
Modifies the set of properties on the current node. Fires
propertiesModifiedEvent
after modifying if the new property set is
different from the old property set (order is irrelevant).
getProperty :: Descriptor d => d -> go (Maybe Property) Source #
Searches for a property on the current node, returning it if found.
getPropertyValue :: ValuedDescriptor v d => d -> go (Maybe v) Source #
Searches for a valued property on the current node, returning its value if found.
putProperty :: Property -> go () Source #
Sets a property on the current node, replacing an existing property with
the same name, if one exists. Fires propertiesModifiedEvent
if the
property has changed.
deleteProperty :: Descriptor d => d -> go () Source #
Deletes a property from the current node, if it's set, and fires
propertiesModifiedEvent
.
Note that although a Property
is a Descriptor
, giving a valued
Property
here will not cause deletion to match on the value of the
property. That is, the following code will result in Nothing
, because
the deletion only cares about the name of the property.
do putProperty $ PL Black deleteProperty $ PL White getPropertyValue propertyPL
modifyProperty :: Descriptor d => d -> (Maybe Property -> Maybe Property) -> go (Either ModifyPropertyError ()) Source #
Calls the given function to modify the state of the given property
(descriptor) on the current node. Nothing
represents the property not
existing on the node, and a Just
marks the property's presence. Fires
propertiesModifiedEvent
if the property changed. This function does not
do any validation to check that the resulting tree state is valid.
The given function is not allowed to change the property into a different
property. Instead, the old property should be removed and the new property
should be inserted separately. If the function does this,
ModifyPropertyCannotChangeType
is returned and no modification takes
place.
modifyPropertyValue :: ValuedDescriptor v d => d -> (Maybe v -> Maybe v) -> go () Source #
Calls the given function to modify the state of the given valued property
(descriptor) on the current node. Nothing
represents the property not
existing on the node, and a Just
with the property's value marks the
property's presence. Fires propertiesModifiedEvent
if the property
changed. This function does not do any validation to check that the
resulting tree state is valid.
modifyPropertyString :: (Stringlike s, ValuedDescriptor s d) => d -> (String -> String) -> go () Source #
Mutates the string-valued property attached to the current node according
to the given function. The input string will be empty if the current node
either has the property with an empty value, or doesn't have the property.
Returning an empty string removes the property from the node, if it was
set. Fires propertiesModifiedEvent
if the property changed.
modifyPropertyList :: ValuedDescriptor [v] d => d -> ([v] -> [v]) -> go () Source #
Mutates the list-valued property attached to the current node according to the given function. The input list will be empty if the current node either has the property with an empty value, or doesn't have the property. Returning an empty list removes the property from the node, if it was set.
Fires propertiesModifiedEvent
if the property changed.
See also modifyPropertyCoords
.
modifyPropertyCoords :: ValuedDescriptor CoordList d => d -> ([Coord] -> [Coord]) -> go () Source #
Mutates the CoordList
-valued property attached to the current node
according to the given function. Conversion between CoordList
and
[Coord]
is performed automatically. The input list will be empty if the
current node either has the property with an empty value, or doesn't have
the property. Returning an empty list removes the property from the node,
if it was set.
Importantly, this might not be specific enough for properties such as DD
and VW
where a present, empty list has different semantics from the
property not being present. In that case, modifyPropertyValue
is better.
Fires propertiesModifiedEvent
if the property changed.
modifyGameInfo :: (GameInfo -> GameInfo) -> go (Either ModifyGameInfoError (GameInfo, GameInfo)) Source #
Mutates the game info for the current path, returning the new info. If
the current node or one of its ancestors has game info properties, then
that node is modified. Otherwise, properties are inserted on the root
node. The return value on success is (oldGameInfo, newGameInfo)
.
The given function is not allowed to modify the RootInfo
within the
GameInfo
. If this happens, an error code is returned and no
modifications are made.
modifyVariationMode :: (VariationMode -> VariationMode) -> go () Source #
Sets the game's VariationMode
via the ST
property on the root node,
then fires a variationModeChangedEvent
if the variation mode has changed.
getAssignedStone :: Coord -> go (Maybe (Maybe Color)) Source #
Retrieves the stone assigned in the current node to a point by AB
,
AE
, or AW
. The possible results are:
Nothing
: No stone has been assigned to the point. The point could still be in any state, e.g. from a play on the current node or some property in an ancestor node.Just Nothing
: The point has been assigned to be empty.Just (Just Color)
: The point has been assigned to have a stone of the given color.
getAllAssignedStones :: go (Map Coord (Maybe Color)) Source #
Looks up all stones that are assigned by AB
, AE
, or AW
properties
on the current node. Returns a map from each point to the stone that is
assigned to the point.
modifyAssignedStones :: [Coord] -> (Maybe (Maybe Color) -> Maybe (Maybe Color)) -> go () Source #
Modifies the state of currently assigned stones, keeping in mind that it
is invalid to mix MoveProperty
and SetupProperty
properties in a single
node. This function has the behaviour of a user changing stone assignments
in a UI. How this function works is:
- Pick a node to work with. If there is a move property on the current node and there is not already a setup property on the current node, then we'll create and modify a new child node. Otherwise, either there are no move properties on the node (so we can add setup properties at will), or there are both move and setup properties on the node (the node is already invalid), so we'll just modify the current node.
- If we're modifying the current node, then apply the modification function
to the state of stone assignment for each coordinate. See
getAssignedStone
for the meaning ofMaybe (Maybe Color)
. Modify the properties in the node as necessary to apply the result (propertiesModifiedEvent
). (NOTE: Currently one event is fired for each property modified; this may change in the future.) - If we need to create a child node, then apply the modification function
to
Nothing
to determine if we're actually adding assignments. If the function returns aJust
, then we create a child node with the necessary assignment properties, insert it (childAddedEvent
), then navigate to it (navigationEvent
). If the function returnsNothing
, thenmodifyAssignedStones
does nothing.
getMark :: Coord -> go (Maybe Mark) Source #
Returns the Mark
at a point on the current node.
modifyMark :: (Maybe Mark -> Maybe Mark) -> Coord -> go () Source #
Calls the given function to modify the presence of a Mark
on the
current node.
addChild :: Node -> go () Source #
Adds a child node to the current node at the end of the current node's
child list. Fires a childAddedEvent
after the child is added.
addChildAt :: Int -> Node -> go () Source #
Adds a child node to the current node at the given index, shifting all
existing children at and after the index to the right. The index must be
in the range [0, numberOfChildren]
; if it is not, it will be capped to
this range. Fires a childAddedEvent
after the child is added.
deleteChildAt :: Int -> go (Either NodeDeleteError ()) Source #
Tries to remove the child node at the given index below the current node. Returns a status code indicating whether the deletion succeeded, or why not.
on :: Event go h -> h -> go () Source #
Registers a new event handler for a given event type.
on0 :: Event go h -> go () -> go () Source #
Registers a new event handler for a given event type. Unlike on
, whose
handler may receive arguments, the handler given here doesn't receive any
arguments.
Instances
The standard monad transformer for MonadGo
.
Instances
runGoT :: Monad m => GoT m a -> Cursor -> m (a, Cursor) Source #
Executes a Go monad transformer on a cursor, returning in the underlying monad a tuple that contains the resulting value and the final cursor.
evalGoT :: Monad m => GoT m a -> Cursor -> m a Source #
Executes a Go monad transformer on a cursor, returning in the underlying monad the value in the transformer.
evalGo :: GoM a -> Cursor -> a Source #
Runs a Go monad on a cursor and returns the value in the monad.
execGoT :: Monad m => GoT m a -> Cursor -> m Cursor Source #
Executes a Go monad transformer on a cursor, returning in the underlying monad the final cursor.
execGo :: GoM a -> Cursor -> Cursor Source #
Runs a Go monad on a cursor and returns the final cursor.
A single step along a game tree. Either up or down.
Errors
All of the types of errors that MonadGo
functions can return.
data NavigationError Source #
Errors from attempting to navigate. Thrown by goUpOrThrow
,
goDownOrThrow
, goLeftOrThrow
, goRightOrThrow
.
NavigationCouldNotMove | Could not make the requested motion. |
Instances
data PopPositionError Source #
Errors from popPosition
.
PopPositionStackEmpty | There is no previous position to return to. No action was taken. |
PopPositionCannotRetraceSteps | The previous position could not be returned to, because the game tree has been modified. The current position in the game tree is where motion reached when it could go no further. This is probably not useful, and computation should be abandoned. |
Instances
Eq PopPositionError Source # | |
Defined in Game.Goatee.Lib.Monad (==) :: PopPositionError -> PopPositionError -> Bool # (/=) :: PopPositionError -> PopPositionError -> Bool # | |
Show PopPositionError Source # | |
Defined in Game.Goatee.Lib.Monad showsPrec :: Int -> PopPositionError -> ShowS # show :: PopPositionError -> String # showList :: [PopPositionError] -> ShowS # |
data DropPositionError Source #
Errors from dropPosition
.
DropPositionStackEmpty | There is no previous position to drop. No action was taken. |
Instances
Eq DropPositionError Source # | |
Defined in Game.Goatee.Lib.Monad (==) :: DropPositionError -> DropPositionError -> Bool # (/=) :: DropPositionError -> DropPositionError -> Bool # | |
Show DropPositionError Source # | |
Defined in Game.Goatee.Lib.Monad showsPrec :: Int -> DropPositionError -> ShowS # show :: DropPositionError -> String # showList :: [DropPositionError] -> ShowS # |
data ModifyPropertyError Source #
Errors from modifyProperty
.
ModifyPropertyCannotChangeType String String | The function attempted to change the property into another property; this is not allowed. No change was made. The two strings are renderings of the old and new property, respectively. |
Instances
Eq ModifyPropertyError Source # | |
Defined in Game.Goatee.Lib.Monad (==) :: ModifyPropertyError -> ModifyPropertyError -> Bool # (/=) :: ModifyPropertyError -> ModifyPropertyError -> Bool # | |
Show ModifyPropertyError Source # | |
Defined in Game.Goatee.Lib.Monad showsPrec :: Int -> ModifyPropertyError -> ShowS # show :: ModifyPropertyError -> String # showList :: [ModifyPropertyError] -> ShowS # |
data ModifyGameInfoError Source #
Errors from modifyGameInfo
.
ModifyGameInfoCannotModifyRootInfo GameInfo GameInfo | The function illegally attempted to modify |
Instances
Eq ModifyGameInfoError Source # | |
Defined in Game.Goatee.Lib.Monad (==) :: ModifyGameInfoError -> ModifyGameInfoError -> Bool # (/=) :: ModifyGameInfoError -> ModifyGameInfoError -> Bool # | |
Show ModifyGameInfoError Source # | |
Defined in Game.Goatee.Lib.Monad showsPrec :: Int -> ModifyGameInfoError -> ShowS # show :: ModifyGameInfoError -> String # showList :: [ModifyGameInfoError] -> ShowS # |
data NodeDeleteError Source #
Errors from calling deleteChildAt
.
NodeDeleteBadIndex | The node couldn't be deleted, because an invalid index was given. |
NodeDeleteOnPathStack | The node couldn't be deleted, because it is on the path stack. |
Instances
Eq NodeDeleteError Source # | |
Defined in Game.Goatee.Lib.Monad (==) :: NodeDeleteError -> NodeDeleteError -> Bool # (/=) :: NodeDeleteError -> NodeDeleteError -> Bool # | |
Show NodeDeleteError Source # | |
Defined in Game.Goatee.Lib.Monad showsPrec :: Int -> NodeDeleteError -> ShowS # show :: NodeDeleteError -> String # showList :: [NodeDeleteError] -> ShowS # |
Throwing monadic actions
goUpOrThrow :: (MonadGo m, MonadError GoError m) => m () Source #
Like goUp
, but throws NavigationCouldNotMove
if at the root of the
tree.
goDownOrThrow :: (MonadGo m, MonadError GoError m) => Int -> m () Source #
Like goDown
, but throws NavigationCouldNotMove
if the requested child
does not exist.
goLeftOrThrow :: (MonadGo m, MonadError GoError m) => m () Source #
Like goLeft
, but throws NavigationCouldNotMove
if there is no left
sibling to move to.
goRightOrThrow :: (MonadGo m, MonadError GoError m) => m () Source #
Like goRight
, but throws NavigationCouldNotMove
if there is no right
sibling to move to.
popPositionOrThrow :: (MonadGo m, MonadError GoError m) => m () Source #
Same as popPosition
, but throws errors rather than returning them.
dropPositionOrThrow :: (MonadGo m, MonadError GoError m) => m () Source #
Same as dropPosition
, but throws errors rather than returning them.
modifyPropertyOrThrow :: (MonadGo m, MonadError GoError m, Descriptor d) => d -> (Maybe Property -> Maybe Property) -> m () Source #
Same as modifyProperty
, but throws errors rather than returning them.
modifyGameInfoOrThrow :: (MonadGo m, MonadError GoError m) => (GameInfo -> GameInfo) -> m (GameInfo, GameInfo) Source #
Same as modifyGameInfo
, but throws errors rather than returning them.
deleteChildAtOrThrow :: (MonadGo m, MonadError GoError m) => Int -> m () Source #
Same as deleteChildAt
, but throws errors rather than returning them.
Event handling
A type of event in a Go monad that can be handled by executing an action.
go
is the type of the Go monad. h
is the handler type, a function that
takes some arguments relating to the event and returns an action in the Go
monad. The arguments to the handler are usually things that would be
difficult to recover from the state of the monad alone, for example the
Step
associated with a navigationEvent
.
The Eq
, Ord
, and Show
instances use events' names, via eventName
.
Instances
Eq (Event go h) Source # | |
Ord (Event go h) Source # | |
Show (Event go h) Source # | |
An existential type for any event in a particular Go monad. Like Event
,
the Eq
, Ord
, and Show
instances use events' names, via eventName
.
Instances
Eq (AnyEvent go) Source # | |
Ord (AnyEvent go) Source # | |
Defined in Game.Goatee.Lib.Monad | |
Show (AnyEvent go) Source # | |
fire :: Monad m => Event (GoT m) h -> (h -> GoT m ()) -> GoT m () Source #
Fires all of the handlers for the given event, using the given function to create a Go action from each of the handlers (normally themselves functions that create Go actions, if they're not just Go actions directly, depending on the event).
eventHandlerFromAction :: Event go h -> go () -> h Source #
Events
childAddedEvent :: Event go (ChildAddedHandler go) Source #
An event corresponding to a child node being added to the current node.
type ChildAddedHandler go = Int -> go () Source #
A handler for childAddedEvent
s. Called with the index of the child added
to the current node.
childDeletedEvent :: Event go (ChildDeletedHandler go) Source #
An event corresponding to the deletion of one of the current node's children.
type ChildDeletedHandler go = Cursor -> go () Source #
A handler for childDeletedEvent
s. It is called with a cursor at the
child that was deleted (this cursor is now out of date).
gameInfoChangedEvent :: Event go (GameInfoChangedHandler go) Source #
An event that is fired when the current game info changes, either by navigating past a node with game info properties, or by modifying the current game info properties.
type GameInfoChangedHandler go = GameInfo -> GameInfo -> go () Source #
A handler for gameInfoChangedEvent
s. It is called with the old game info
then the new game info.
navigationEvent :: Event go (NavigationHandler go) Source #
An event that is fired when a single step up or down in a game tree is made.
type NavigationHandler go = Step -> go () Source #
A handler for navigationEvent
s.
A navigation handler may navigate further, but beware infinite recursion. A navigation handler must end on the same node on which it started.
propertiesModifiedEvent :: Event go (PropertiesModifiedHandler go) Source #
An event corresponding to a modification to the properties list of the current node.
type PropertiesModifiedHandler go = [Property] -> [Property] -> go () Source #
A handler for propertiesModifiedEvent
s. It is called with the old
property list then the new property list.
variationModeChangedEvent :: Event go (VariationModeChangedHandler go) Source #
An event corresponding to a change in the active VariationMode
. This can
happen when modifying the ST
property, and also when navigating between
collections (as they have different root nodes).
type VariationModeChangedHandler go = VariationMode -> VariationMode -> go () Source #
A handler for variationModeChangedEvent
s. It is called with the old
variation mode then the new variation mode.