ADPfusion-0.4.0.0: ADP/Fusion/Base/Classes.hs
module ADP.Fusion.Base.Classes where
import Data.Strict.Tuple
import Data.Vector.Fusion.Stream.Size
import qualified Data.Vector.Fusion.Stream.Monadic as S
import Data.PrimitiveArray
data OutsideContext s
= OStatic s
| ORightOf s
| OFirstLeft s
| OLeftOf s
data InsideContext s
= IStatic s
| IVariable s
data ComplementContext
= Complemented
class RuleContext i where
type Context i :: *
initialContext :: i -> Context i
-- | During construction of the stream, we need to extract individual elements
-- from symbols in production rules. An element in a stream is fixed by both,
-- the type @x@ of the actual argument we want to grab (say individual
-- characters we parse from an input) and the type of indices @i@ we use.
--
-- @Elm@ data constructors are all eradicated during fusion and should never
-- show up in CORE.
class Element x i where
data Elm x i :: *
type Arg x :: *
getArg :: Elm x i -> Arg x
getIdx :: Elm x i -> i
getOmx :: Elm x i -> i
-- | @mkStream@ creates the actual stream of elements (@Elm@) that will be fed
-- to functions on the left of the @(<<<)@ operator. Streams work over all
-- monads and are specialized for each combination of arguments @x@ and indices
-- @i@.
class (Monad m) => MkStream m x i where
mkStream :: x -> Context i -> i -> i -> S.Stream m (Elm x i)
-- | Finally, we need to be able to correctly build together symbols on the
-- right-hand side of the @(<<<)@ operator.
--
-- The default makes sure that the last (or only) argument left over is
-- correctly assigned a @Z@ to terminate the symbol stack.
class Build x where
type Stack x :: *
type Stack x = S :!: x
build :: x -> Stack x
default build :: (Stack x ~ (S :!: x)) => x -> Stack x
build x = S :!: x
{-# Inline build #-}
instance Build x => Build (x:!:y) where
type Stack (x:!:y) = Stack x :!: y
build (x:!:y) = build x :!: y
{-# Inline build #-}
-- | Similar to 'Z', but terminates an argument stack.
data S = S
deriving (Eq,Show)
instance
(
) => Element S i where
data Elm S i = ElmS !i !i
type Arg S = Z
getArg (ElmS _ _) = Z
getIdx (ElmS i _) = i
getOmx (ElmS _ o) = o
{-# Inline getArg #-}
{-# Inline getIdx #-}
{-# Inline getOmx #-}
deriving instance Show ix => Show (Elm S ix)
-- | 'staticCheck' acts as a static filter. If 'b' is true, we keep all stream
-- elements. If 'b' is false, we discard all stream elements.
staticCheck :: Monad m => Bool -> S.Stream m a -> S.Stream m a
staticCheck b (S.Stream step t n) = b `seq` S.Stream snew (CheckLeft (b:.t)) (toMax n) where
{-# Inline [0] snew #-}
snew (CheckLeft (False:._)) = return $ S.Done
snew (CheckLeft (True :.s)) = return $ S.Skip (CheckRight s)
snew (CheckRight s ) = do r <- step s
case r of
S.Yield x s' -> return $ S.Yield x (CheckRight s')
S.Skip s' -> return $ S.Skip (CheckRight s')
S.Done -> return $ S.Done
{-# INLINE staticCheck #-}
data StaticCheck a b = CheckLeft a | CheckRight b
-- | Constrains the behaviour of the memoizing tables. They may be 'EmptyOk' if
-- @i==j@ is allowed (empty subwords or similar); or they may need 'NonEmpty'
-- indices, or finally they can be 'OnlyZero' (only @i==j@ allowed) which is
-- useful in multi-dimensional casese.
data TableConstraint
= EmptyOk
| NonEmpty
| OnlyZero
deriving (Eq,Show)
minSize :: TableConstraint -> Int
minSize NonEmpty = 1
minSize _ = 0
{-# INLINE minSize #-}
class ModifyConstraint t where
toNonEmpty :: t -> t
toEmpty :: t -> t
-- |
type family TblConstraint x :: *
type instance TblConstraint (is:.i) = TblConstraint is :. TblConstraint i
type instance TblConstraint Z = Z
type instance TblConstraint (Outside o) = TblConstraint o
type instance TblConstraint (Complement o) = TblConstraint o
-- TODO move into the sub-modules
type instance TblConstraint PointL = TableConstraint
type instance TblConstraint PointR = TableConstraint
type instance TblConstraint Subword = TableConstraint