module LogicGrowsOnTrees.Location
(
MonadLocatable(..)
, Location
, Solution(..)
, LocatableT(..)
, LocatableTree
, LocatableTreeIO
, LocatableTreeT(..)
, applyCheckpointCursorToLocation
, applyContextToLocation
, applyPathToLocation
, branchingFromLocation
, labelFromBranching
, labelFromContext
, labelFromPath
, leftBranchOf
, locationTransformerForBranchChoice
, normalizeLocatableTree
, normalizeLocatableTreeT
, rightBranchOf
, rootLocation
, runLocatableT
, sendTreeDownLocation
, sendTreeTDownLocation
, solutionsToMap
, exploreLocatableTree
, exploreLocatableTreeT
, exploreLocatableTreeTAndIgnoreResults
, exploreTreeWithLocations
, exploreTreeTWithLocations
, exploreTreeWithLocationsStartingAt
, exploreTreeTWithLocationsStartingAt
, exploreLocatableTreeUntilFirst
, exploreLocatableTreeUntilFirstT
, exploreTreeUntilFirstWithLocation
, exploreTreeTUntilFirstWithLocation
, exploreTreeUntilFirstWithLocationStartingAt
, exploreTreeTUntilFirstWithLocationStartingAt
) where
import Control.Applicative (Alternative(..),Applicative(..))
import Control.Exception (throw)
import Control.Monad (MonadPlus(..),(>=>),liftM,liftM2)
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad.Operational (ProgramViewT(..),viewT)
import Control.Monad.Trans.Class (MonadTrans(..))
import Control.Monad.Trans.Reader (ReaderT(..),ask)
import Data.Composition
import qualified Data.Map as Map
import Data.Map (Map)
import Data.Maybe (fromJust)
import Data.Monoid
import Data.Foldable as Fold
import Data.Function (on)
import Data.Functor.Identity (Identity,runIdentity)
import Data.Sequence (viewl,ViewL(..))
import Data.SequentialIndex (SequentialIndex,root,leftChild,rightChild)
import LogicGrowsOnTrees
import LogicGrowsOnTrees.Checkpoint
import LogicGrowsOnTrees.Path
class MonadPlus m ⇒ MonadLocatable m where
getLocation :: m Location
newtype Location = Location { unwrapLocation :: SequentialIndex } deriving (Eq)
data Solution α = Solution
{ solutionLocation :: Location
, solutionResult :: α
} deriving (Eq,Ord,Show)
instance Monoid Location where
mempty = rootLocation
xl@(Location x) `mappend` yl@(Location y)
| x == root = yl
| y == root = xl
| otherwise = Location $ go y root x
where
go original_label current_label product_label =
case current_label `compare` original_label of
EQ → product_label
GT → (go original_label `on` (fromJust . leftChild)) current_label product_label
LT → (go original_label `on` (fromJust . rightChild)) current_label product_label
instance Ord Location where
compare = compare `on` branchingFromLocation
instance Show Location where
show = fmap (\branch → case branch of {LeftBranch → 'L'; RightBranch → 'R'}) . branchingFromLocation
newtype LocatableT m α = LocatableT { unwrapLocatableT :: ReaderT Location m α }
deriving (Applicative,Functor,Monad,MonadIO,MonadTrans)
instance (Alternative m, Monad m) ⇒ Alternative (LocatableT m) where
empty = LocatableT $ lift empty
LocatableT left <|> LocatableT right = LocatableT . ReaderT $
\branch → (runReaderT left (leftBranchOf branch)) <|> (runReaderT right (rightBranchOf branch))
instance MonadPlus m ⇒ MonadLocatable (LocatableT m) where
getLocation = LocatableT $ ask
instance MonadPlus m ⇒ MonadPlus (LocatableT m) where
mzero = LocatableT $ lift mzero
LocatableT left `mplus` LocatableT right = LocatableT . ReaderT $
\branch → (runReaderT left (leftBranchOf branch)) `mplus` (runReaderT right (rightBranchOf branch))
instance MonadExplorableTrans m ⇒ MonadExplorableTrans (LocatableT m) where
type NestedMonad (LocatableT m) = NestedMonad m
runAndCache = LocatableT . lift . runAndCache
runAndCacheGuard = LocatableT . lift . runAndCacheGuard
runAndCacheMaybe = LocatableT . lift . runAndCacheMaybe
instance MonadPlus m ⇒ Monoid (LocatableT m α) where
mempty = mzero
mappend = mplus
type LocatableTree = LocatableTreeT Identity
type LocatableTreeIO = LocatableTreeT IO
newtype LocatableTreeT m α = LocatableTreeT { unwrapLocatableTreeT :: LocatableT (TreeT m) α }
deriving (Alternative,Applicative,Functor,Monad,MonadIO,MonadLocatable,MonadPlus,Monoid)
instance MonadTrans LocatableTreeT where
lift = LocatableTreeT . lift . lift
instance Monad m ⇒ MonadExplorableTrans (LocatableTreeT m) where
type NestedMonad (LocatableTreeT m) = m
runAndCache = LocatableTreeT . runAndCache
runAndCacheGuard = LocatableTreeT . runAndCacheGuard
runAndCacheMaybe = LocatableTreeT . runAndCacheMaybe
applyCheckpointCursorToLocation ::
CheckpointCursor →
Location →
Location
applyCheckpointCursorToLocation cursor =
case viewl cursor of
EmptyL → id
step :< rest →
applyCheckpointCursorToLocation rest
.
case step of
CachePointD _ → id
ChoicePointD active_branch _ → locationTransformerForBranchChoice active_branch
applyContextToLocation ::
Context m α →
Location →
Location
applyContextToLocation context =
case viewl context of
EmptyL → id
step :< rest →
applyContextToLocation rest
.
case step of
CacheContextStep _ → id
LeftBranchContextStep _ _ → leftBranchOf
RightBranchContextStep → rightBranchOf
applyPathToLocation ::
Path →
Location →
Location
applyPathToLocation path =
case viewl path of
EmptyL → id
step :< rest →
applyPathToLocation rest
.
case step of
ChoiceStep active_branch → locationTransformerForBranchChoice active_branch
CacheStep _ → id
branchingFromLocation :: Location → [BranchChoice]
branchingFromLocation = go root . unwrapLocation
where
go current_label original_label =
case current_label `compare` original_label of
EQ → []
GT → LeftBranch:go (fromJust . leftChild $ current_label) original_label
LT → RightBranch:go (fromJust . rightChild $ current_label) original_label
labelFromBranching :: Foldable t ⇒ t BranchChoice → Location
labelFromBranching = Fold.foldl' (flip locationTransformerForBranchChoice) rootLocation
labelFromContext :: Context m α → Location
labelFromContext = flip applyContextToLocation rootLocation
labelFromPath :: Path → Location
labelFromPath = flip applyPathToLocation rootLocation
leftBranchOf :: Location → Location
leftBranchOf = Location . fromJust . leftChild . unwrapLocation
locationTransformerForBranchChoice :: BranchChoice → (Location → Location)
locationTransformerForBranchChoice LeftBranch = leftBranchOf
locationTransformerForBranchChoice RightBranch = rightBranchOf
normalizeLocatableTree :: LocatableTree α → Tree α
normalizeLocatableTree = runLocatableT . unwrapLocatableTreeT
normalizeLocatableTreeT :: LocatableTreeT m α → TreeT m α
normalizeLocatableTreeT = runLocatableT . unwrapLocatableTreeT
rightBranchOf :: Location → Location
rightBranchOf = Location . fromJust . rightChild . unwrapLocation
rootLocation :: Location
rootLocation = Location root
runLocatableT :: LocatableT m α → m α
runLocatableT = flip runReaderT rootLocation . unwrapLocatableT
sendTreeDownLocation :: Location → Tree α → Tree α
sendTreeDownLocation label = runIdentity . sendTreeTDownLocation label
sendTreeTDownLocation :: Monad m ⇒ Location → TreeT m α → m (TreeT m α)
sendTreeTDownLocation (Location label) = go root
where
go parent tree
| parent == label = return tree
| otherwise =
(viewT . unwrapTreeT) tree >>= \view → case view of
Return _ → throw TreeEndedBeforeEndOfWalk
Null :>>= _ → throw TreeEndedBeforeEndOfWalk
ProcessPendingRequests :>>= k → go parent . TreeT . k $ ()
Cache mx :>>= k → mx >>= maybe (throw TreeEndedBeforeEndOfWalk) (go parent . TreeT . k)
Choice left right :>>= k →
if parent > label
then
go
(fromJust . leftChild $ parent)
(left >>= TreeT . k)
else
go
(fromJust . rightChild $ parent)
(right >>= TreeT . k)
solutionsToMap :: Foldable t ⇒ t (Solution α) → Map Location α
solutionsToMap = Fold.foldl' (flip $ \(Solution label solution) → Map.insert label solution) Map.empty
exploreLocatableTree :: Monoid α ⇒ LocatableTree α → α
exploreLocatableTree = exploreTree . runLocatableT . unwrapLocatableTreeT
exploreLocatableTreeT :: (Monoid α,Monad m) ⇒ LocatableTreeT m α → m α
exploreLocatableTreeT = exploreTreeT . runLocatableT . unwrapLocatableTreeT
exploreLocatableTreeTAndIgnoreResults :: Monad m ⇒ LocatableTreeT m α → m ()
exploreLocatableTreeTAndIgnoreResults = exploreTreeTAndIgnoreResults . runLocatableT . unwrapLocatableTreeT
exploreTreeWithLocations :: Tree α → [Solution α]
exploreTreeWithLocations = runIdentity . exploreTreeTWithLocations
exploreTreeTWithLocations :: Monad m ⇒ TreeT m α → m [Solution α]
exploreTreeTWithLocations = exploreTreeTWithLocationsStartingAt rootLocation
exploreTreeWithLocationsStartingAt :: Location → Tree α → [Solution α]
exploreTreeWithLocationsStartingAt = runIdentity .* exploreTreeTWithLocationsStartingAt
exploreTreeTWithLocationsStartingAt :: Monad m ⇒ Location → TreeT m α → m [Solution α]
exploreTreeTWithLocationsStartingAt label =
viewT . unwrapTreeT >=> \view →
case view of
Return x → return [Solution label x]
Cache mx :>>= k → mx >>= maybe (return []) (exploreTreeTWithLocationsStartingAt label . TreeT . k)
Choice left right :>>= k →
liftM2 (++)
(exploreTreeTWithLocationsStartingAt (leftBranchOf label) $ left >>= TreeT . k)
(exploreTreeTWithLocationsStartingAt (rightBranchOf label) $ right >>= TreeT . k)
Null :>>= _ → return []
ProcessPendingRequests :>>= k → exploreTreeTWithLocationsStartingAt label . TreeT . k $ ()
exploreLocatableTreeUntilFirst :: LocatableTree α → Maybe α
exploreLocatableTreeUntilFirst = exploreTreeUntilFirst . runLocatableT . unwrapLocatableTreeT
exploreLocatableTreeUntilFirstT :: Monad m ⇒ LocatableTreeT m α → m (Maybe α)
exploreLocatableTreeUntilFirstT = exploreTreeTUntilFirst . runLocatableT . unwrapLocatableTreeT
exploreTreeUntilFirstWithLocation :: Tree α → Maybe (Solution α)
exploreTreeUntilFirstWithLocation = runIdentity . exploreTreeTUntilFirstWithLocation
exploreTreeTUntilFirstWithLocation :: Monad m ⇒ TreeT m α → m (Maybe (Solution α))
exploreTreeTUntilFirstWithLocation = exploreTreeTUntilFirstWithLocationStartingAt rootLocation
exploreTreeUntilFirstWithLocationStartingAt :: Location → Tree α → Maybe (Solution α)
exploreTreeUntilFirstWithLocationStartingAt = runIdentity .* exploreTreeTUntilFirstWithLocationStartingAt
exploreTreeTUntilFirstWithLocationStartingAt :: Monad m ⇒ Location → TreeT m α → m (Maybe (Solution α))
exploreTreeTUntilFirstWithLocationStartingAt = go .* exploreTreeTWithLocationsStartingAt
where
go = liftM $ \solutions →
case solutions of
[] → Nothing
(x:_) → Just x