Skip to content
Snippets Groups Projects
RTree.hs 3.31 KiB
Newer Older
  • Learn to ignore specific revisions
  • chrg's avatar
    chrg committed
    {-# LANGUAGE BlockArguments #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE DeriveFunctor #-}
    {-# LANGUAGE DerivingVia #-}
    {-# LANGUAGE FlexibleContexts #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE FlexibleInstances #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE KindSignatures #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE LambdaCase #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE MultiParamTypeClasses #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE RankNTypes #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE ScopedTypeVariables #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE UndecidableInstances #-}
    
    chrg's avatar
    chrg committed
    {-# LANGUAGE ViewPatterns #-}
    
    chrg's avatar
    chrg committed
    
    
    chrg's avatar
    chrg committed
    {- |
    Module: Control.RTree
    -}
    
    chrg's avatar
    chrg committed
    module Control.RTree where
    
    
    chrg's avatar
    chrg committed
    import Control.Applicative
    import Control.Monad.Reader
    import Control.Monad.Trans.Maybe
    
    chrg's avatar
    chrg committed
    import Data.Functor.Identity
    
    chrg's avatar
    chrg committed
    import qualified Data.Map.Strict as Map
    import Data.Maybe
    import GHC.IORef
    
    chrg's avatar
    chrg committed
    
    
    chrg's avatar
    chrg committed
    import Control.Monad.Reduce
    import Control.Monad.State.Strict
    
    chrg's avatar
    chrg committed
    
    
    chrg's avatar
    chrg committed
    data RTree l i
      = Split (RTree l i) !(RTree l i)
      | SplitOn !l (RTree l i) !(RTree l i)
    
    chrg's avatar
    chrg committed
      | Done i
    
    chrg's avatar
    chrg committed
      deriving (Functor)
    
    chrg's avatar
    chrg committed
    
    
    chrg's avatar
    chrg committed
    extract :: RTree l i -> i
    extract = \case
      Split _ rhs -> extract rhs
      SplitOn _ _ rhs -> extract rhs
    
    chrg's avatar
    chrg committed
      Done v -> v
    
    
    chrg's avatar
    chrg committed
    instance Applicative (RTree l) where
    
    chrg's avatar
    chrg committed
      pure = Done
      (<*>) = ap
    
    
    chrg's avatar
    chrg committed
    instance Monad (RTree l) where
    
    chrg's avatar
    chrg committed
      ma >>= f = case ma of
        Done i -> f i
    
    chrg's avatar
    chrg committed
        Split lhs rhs ->
          Split (lhs >>= f) (rhs >>= f)
        SplitOn l lhs rhs ->
          SplitOn l (lhs >>= f) (rhs >>= f)
    
    chrg's avatar
    chrg committed
    
    
    chrg's avatar
    chrg committed
    instance MonadReduce l (RTree l) where
    
    chrg's avatar
    chrg committed
      splitWith = \case
    
    chrg's avatar
    chrg committed
        Just n -> SplitOn n
        Nothing -> Split
    
    chrg's avatar
    chrg committed
    
    
    chrg's avatar
    chrg committed
    reduce
    
    chrg's avatar
    chrg committed
      :: forall m l i
       . (Alternative m)
      => (i -> m ())
    
    chrg's avatar
    chrg committed
      -> RTree l i
    
    chrg's avatar
    chrg committed
      -> m i
    
    chrg's avatar
    chrg committed
    reduce p = checkgo
    
    chrg's avatar
    chrg committed
     where
      go = \case
        (Done i) -> pure i
    
    chrg's avatar
    chrg committed
        (Split lhs rhs) -> (checkgo lhs <|> go rhs)
        (SplitOn _ lhs rhs) -> (checkgo lhs <|> go rhs)
    
    chrg's avatar
    chrg committed
      checkgo rt = p (extract rt) *> go rt
    {-# SPECIALIZE reduce :: (i -> MaybeT IO ()) -> RTree l i -> MaybeT IO i #-}
    
    type Valuation l = Map.Map l Bool
    
    extractL :: (Ord l) => Valuation l -> RTree l i -> i
    extractL v = \case
      Split _ rhs -> extractL v rhs
      SplitOn l lhs rhs -> case Map.lookup l v of
        Just False -> extractL v lhs
        _ -> extractL v rhs
      Done i -> i
    
    reduceL
      :: forall m l i
       . (Alternative m, Ord l)
      => (Valuation l -> i -> m ())
      -> Valuation l
      -> RTree l i
      -> m i
    reduceL p = checkgo
     where
      checkgo v r = p v (extractL v r) *> go v r
      go v = \case
        Done i -> pure i
        SplitOn l lhs rhs -> case Map.lookup l v of
          Just True -> checkgo v rhs
          Just False -> checkgo v lhs
          Nothing -> checkgo (Map.insert l False v) lhs <|> go (Map.insert l True v) rhs
        Split lhs rhs -> (checkgo v lhs <|> go v rhs)
    {-# INLINE reduceL #-}
    
    data ReState l = ReState ![Bool] !(Valuation l)
    
    
    chrg's avatar
    chrg committed
    newtype IRTree l i = IRTree {runIRTree :: ReState l -> (i, ReState l)}
      deriving (Functor, Applicative, Monad) via (State (ReState l))
    
    instance (Ord l) => MonadReduce l (IRTree l) where
      checkWith = \case
        Nothing ->
          IRTree \case
            ReState (a : as) v -> (a, ReState as v)
            ReState [] v -> (False, ReState [] v)
        Just l -> IRTree \case
          ReState as v@(Map.lookup l -> Just x) -> (not x, ReState as v)
          ReState (a : as) v -> (a, ReState as (Map.insert l (not a) v))
          ReState [] v -> (False, ReState [] (Map.insert l True v))
    
    reduceI
    
    chrg's avatar
    chrg committed
      :: forall m l i
    
    chrg's avatar
    chrg committed
       . (Monad m, Ord l)
      => (Valuation l -> i -> m Bool)
    
    chrg's avatar
    chrg committed
      -> Valuation l
    
    chrg's avatar
    chrg committed
      -> IRTree l i
      -> m i
    reduceI p v (IRTree m) = go []
    
    chrg's avatar
    chrg committed
     where
    
    chrg's avatar
    chrg committed
      go pth =
        case m (ReState pth v) of
          (i, ReState [] v') -> do
            t <- p v' i
            go (pth <> [t])
          (i, _) -> pure i
    {-# INLINE reduceI #-}