packages feed

pred-trie 0.4.1 → 0.5.0

raw patch · 9 files changed

+688/−327 lines, 9 filesdep +poly-arityPVP ok

version bump matches the API change (PVP)

Dependencies added: poly-arity

API changes (from Hackage documentation)

- Data.Trie.Pred: PredTrie :: !(HashMapStep PredTrie k a) -> !(PredSteps PredTrie k a) -> PredTrie k a
- Data.Trie.Pred: RootedPredTrie :: !(Maybe a) -> !(PredTrie k a) -> RootedPredTrie k a
- Data.Trie.Pred: [predLits] :: PredTrie k a -> !(HashMapStep PredTrie k a)
- Data.Trie.Pred: [predPreds] :: PredTrie k a -> !(PredSteps PredTrie k a)
- Data.Trie.Pred: [rootedBase] :: RootedPredTrie k a -> !(Maybe a)
- Data.Trie.Pred: [rootedSub] :: RootedPredTrie k a -> !(PredTrie k a)
- Data.Trie.Pred: data PredTrie k a
- Data.Trie.Pred: data RootedPredTrie k a
- Data.Trie.Pred: emptyPT :: PredTrie k a
- Data.Trie.Pred: emptyRPT :: RootedPredTrie k a
- Data.Trie.Pred: instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k) => Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty k Data.Trie.Pred.PredTrie
- Data.Trie.Pred: instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k) => Data.Trie.Class.Trie [] k Data.Trie.Pred.RootedPredTrie
- Data.Trie.Pred: instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k) => GHC.Base.Monoid (Data.Trie.Pred.PredTrie k a)
- Data.Trie.Pred: instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k) => GHC.Base.Monoid (Data.Trie.Pred.RootedPredTrie k a)
- Data.Trie.Pred: instance (GHC.Show.Show k, GHC.Show.Show a) => GHC.Show.Show (Data.Trie.Pred.PredTrie k a)
- Data.Trie.Pred: instance (GHC.Show.Show k, GHC.Show.Show a) => GHC.Show.Show (Data.Trie.Pred.RootedPredTrie k a)
- Data.Trie.Pred: instance (Test.QuickCheck.Arbitrary.Arbitrary k, Test.QuickCheck.Arbitrary.Arbitrary a, GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => Test.QuickCheck.Arbitrary.Arbitrary (Data.Trie.Pred.PredTrie k a)
- Data.Trie.Pred: instance GHC.Base.Functor (Data.Trie.Pred.PredTrie k)
- Data.Trie.Pred: instance GHC.Base.Functor (Data.Trie.Pred.RootedPredTrie k)
- Data.Trie.Pred: matchPT :: (Hashable k, Eq k) => NonEmpty k -> PredTrie k a -> Maybe (NonEmpty k, a, [k])
- Data.Trie.Pred: matchRPT :: (Hashable k, Eq k) => [k] -> RootedPredTrie k a -> Maybe ([k], a, [k])
- Data.Trie.Pred: matchesPT :: (Hashable k, Eq k) => NonEmpty k -> PredTrie k a -> [(NonEmpty k, a, [k])]
- Data.Trie.Pred: matchesRPT :: (Hashable k, Eq k) => [k] -> RootedPredTrie k a -> [([k], a, [k])]
- Data.Trie.Pred.Step: PredStep :: {-# UNPACK #-} !Text -> !(s -> Maybe r) -> !(Maybe (r -> a)) -> !(c s (r -> a)) -> PredStep c s a
- Data.Trie.Pred.Step: PredSteps :: [PredStep c s a] -> PredSteps c s a
- Data.Trie.Pred.Step: [predData] :: PredStep c s a -> !(Maybe (r -> a))
- Data.Trie.Pred.Step: [predPred] :: PredStep c s a -> !(s -> Maybe r)
- Data.Trie.Pred.Step: [predSub] :: PredStep c s a -> !(c s (r -> a))
- Data.Trie.Pred.Step: [predTag] :: PredStep c s a -> {-# UNPACK #-} !Text
- Data.Trie.Pred.Step: [unPredSteps] :: PredSteps c s a -> [PredStep c s a]
- Data.Trie.Pred.Step: data PredStep c s a
- Data.Trie.Pred.Step: instance Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty s c => Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty s (Data.Trie.Pred.Step.PredStep c)
- Data.Trie.Pred.Step: instance Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty s c => Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty s (Data.Trie.Pred.Step.PredSteps c)
- Data.Trie.Pred.Step: instance GHC.Base.Functor (c s) => GHC.Base.Functor (Data.Trie.Pred.Step.PredStep c s)
- Data.Trie.Pred.Step: instance GHC.Base.Functor (c s) => GHC.Base.Functor (Data.Trie.Pred.Step.PredSteps c s)
- Data.Trie.Pred.Step: instance GHC.Classes.Eq s => GHC.Base.Monoid (Data.Trie.Pred.Step.PredSteps c s a)
- Data.Trie.Pred.Step: instance GHC.Show.Show s => GHC.Show.Show (Data.Trie.Pred.Step.PredStep c s a)
- Data.Trie.Pred.Step: instance GHC.Show.Show s => GHC.Show.Show (Data.Trie.Pred.Step.PredSteps c s a)
- Data.Trie.Pred.Step: newtype PredSteps c s a
- Data.Trie.Pred.Step: singletonPred :: Monoid (c s (r -> a)) => Text -> (s -> Maybe r) -> (r -> a) -> PredStep c s a
- Data.Trie.Pred.Step: unionPred :: PredSteps c s a -> PredSteps c s a -> PredSteps c s a
+ Data.Trie.Pred.Base: PredTrie :: !(HashMapStep PredTrie k a) -> !(PredSteps k PredTrie k a) -> PredTrie k a
+ Data.Trie.Pred.Base: RootedPredTrie :: !(Maybe a) -> !(PredTrie k a) -> RootedPredTrie k a
+ Data.Trie.Pred.Base: [predLits] :: PredTrie k a -> !(HashMapStep PredTrie k a)
+ Data.Trie.Pred.Base: [predPreds] :: PredTrie k a -> !(PredSteps k PredTrie k a)
+ Data.Trie.Pred.Base: [rootedBase] :: RootedPredTrie k a -> !(Maybe a)
+ Data.Trie.Pred.Base: [rootedSub] :: RootedPredTrie k a -> !(PredTrie k a)
+ Data.Trie.Pred.Base: data PredTrie k a
+ Data.Trie.Pred.Base: data RootedPredTrie k a
+ Data.Trie.Pred.Base: emptyPT :: PredTrie k a
+ Data.Trie.Pred.Base: emptyRPT :: RootedPredTrie k a
+ Data.Trie.Pred.Base: instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k) => Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty k Data.Trie.Pred.Base.PredTrie
+ Data.Trie.Pred.Base: instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k) => Data.Trie.Class.Trie [] k Data.Trie.Pred.Base.RootedPredTrie
+ Data.Trie.Pred.Base: instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k) => GHC.Base.Monoid (Data.Trie.Pred.Base.PredTrie k a)
+ Data.Trie.Pred.Base: instance (Data.Hashable.Class.Hashable k, GHC.Classes.Eq k) => GHC.Base.Monoid (Data.Trie.Pred.Base.RootedPredTrie k a)
+ Data.Trie.Pred.Base: instance (GHC.Show.Show k, GHC.Show.Show a) => GHC.Show.Show (Data.Trie.Pred.Base.PredTrie k a)
+ Data.Trie.Pred.Base: instance (GHC.Show.Show k, GHC.Show.Show a) => GHC.Show.Show (Data.Trie.Pred.Base.RootedPredTrie k a)
+ Data.Trie.Pred.Base: instance (Test.QuickCheck.Arbitrary.Arbitrary k, Test.QuickCheck.Arbitrary.Arbitrary a, GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => Test.QuickCheck.Arbitrary.Arbitrary (Data.Trie.Pred.Base.PredTrie k a)
+ Data.Trie.Pred.Base: instance GHC.Base.Functor (Data.Trie.Pred.Base.PredTrie k)
+ Data.Trie.Pred.Base: instance GHC.Base.Functor (Data.Trie.Pred.Base.RootedPredTrie k)
+ Data.Trie.Pred.Base: matchPT :: (Hashable k, Eq k) => NonEmpty k -> PredTrie k a -> Maybe (NonEmpty k, a, [k])
+ Data.Trie.Pred.Base: matchRPT :: (Hashable k, Eq k) => [k] -> RootedPredTrie k a -> Maybe ([k], a, [k])
+ Data.Trie.Pred.Base: matchesPT :: (Hashable k, Eq k) => NonEmpty k -> PredTrie k a -> [(NonEmpty k, a, [k])]
+ Data.Trie.Pred.Base: matchesRPT :: (Hashable k, Eq k) => [k] -> RootedPredTrie k a -> [([k], a, [k])]
+ Data.Trie.Pred.Base.Step: PredStep :: !k -> !(s -> Maybe r) -> !(Maybe (r -> a)) -> !(c s (r -> a)) -> PredStep k c s a
+ Data.Trie.Pred.Base.Step: PredSteps :: [PredStep k c s a] -> PredSteps k c s a
+ Data.Trie.Pred.Base.Step: [predData] :: PredStep k c s a -> !(Maybe (r -> a))
+ Data.Trie.Pred.Base.Step: [predPred] :: PredStep k c s a -> !(s -> Maybe r)
+ Data.Trie.Pred.Base.Step: [predSub] :: PredStep k c s a -> !(c s (r -> a))
+ Data.Trie.Pred.Base.Step: [predTag] :: PredStep k c s a -> !k
+ Data.Trie.Pred.Base.Step: [unPredSteps] :: PredSteps k c s a -> [PredStep k c s a]
+ Data.Trie.Pred.Base.Step: data PredStep k c s a
+ Data.Trie.Pred.Base.Step: instance (GHC.Classes.Eq s, GHC.Classes.Eq k) => GHC.Base.Monoid (Data.Trie.Pred.Base.Step.PredSteps k c s a)
+ Data.Trie.Pred.Base.Step: instance (GHC.Show.Show k, GHC.Show.Show s) => GHC.Show.Show (Data.Trie.Pred.Base.Step.PredSteps k c s a)
+ Data.Trie.Pred.Base.Step: instance (GHC.Show.Show s, GHC.Show.Show k) => GHC.Show.Show (Data.Trie.Pred.Base.Step.PredStep k c s a)
+ Data.Trie.Pred.Base.Step: instance Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty s c => Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty s (Data.Trie.Pred.Base.Step.PredStep k c)
+ Data.Trie.Pred.Base.Step: instance Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty s c => Data.Trie.Class.Trie Data.List.NonEmpty.NonEmpty s (Data.Trie.Pred.Base.Step.PredSteps k c)
+ Data.Trie.Pred.Base.Step: instance GHC.Base.Functor (c s) => GHC.Base.Functor (Data.Trie.Pred.Base.Step.PredStep k c s)
+ Data.Trie.Pred.Base.Step: instance GHC.Base.Functor (c s) => GHC.Base.Functor (Data.Trie.Pred.Base.Step.PredSteps k c s)
+ Data.Trie.Pred.Base.Step: newtype PredSteps k c s a
+ Data.Trie.Pred.Base.Step: singletonPred :: Monoid (c s (r -> a)) => k -> (s -> Maybe r) -> (r -> a) -> PredStep k c s a
+ Data.Trie.Pred.Base.Step: unionPred :: (Eq k) => PredSteps k c s a -> PredSteps k c s a -> PredSteps k c s a
+ Data.Trie.Pred.Interface: (./) :: PathChunk k mx -> PathChunks k xs -> PathChunks k (mx : xs)
+ Data.Trie.Pred.Interface: PTBuilderT :: StateT (RootedPredTrie k v) m a -> PTBuilderT k v m a
+ Data.Trie.Pred.Interface: [runPTBuilderT] :: PTBuilderT k v m a -> StateT (RootedPredTrie k v) m a
+ Data.Trie.Pred.Interface: data PathChunk k (mx :: Maybe *)
+ Data.Trie.Pred.Interface: data PathChunks k (xs :: [Maybe *])
+ Data.Trie.Pred.Interface: data RootedPredTrie k a
+ Data.Trie.Pred.Interface: delete :: (Eq k, Hashable k) => [k] -> RootedPredTrie k a -> RootedPredTrie k a
+ Data.Trie.Pred.Interface: execPTBuilderT :: (Monad m, Eq k, Hashable k) => PTBuilderT k v m a -> m (RootedPredTrie k v)
+ Data.Trie.Pred.Interface: insert :: (Monad m, Eq k, Hashable k, Singleton (PathChunks k xs) childContent (RootedPredTrie k resultContent), cleanxs ~ CatMaybes xs, ArityTypeListIso childContent cleanxs resultContent) => PathChunks k xs -> childContent -> PTBuilderT k resultContent m ()
+ Data.Trie.Pred.Interface: insertHere :: (Monad m, Eq k, Hashable k) => v -> PTBuilderT k v m ()
+ Data.Trie.Pred.Interface: instance (GHC.Base.Monad m, GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => Control.Monad.Writer.Class.MonadWriter (Data.Trie.Pred.Base.RootedPredTrie k v) (Data.Trie.Pred.Interface.PTBuilderT k v m)
+ Data.Trie.Pred.Interface: instance Control.Monad.Trans.Class.MonadTrans (Data.Trie.Pred.Interface.PTBuilderT k v)
+ Data.Trie.Pred.Interface: instance GHC.Base.Functor m => GHC.Base.Functor (Data.Trie.Pred.Interface.PTBuilderT k v m)
+ Data.Trie.Pred.Interface: instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState (Data.Trie.Pred.Base.RootedPredTrie k v) (Data.Trie.Pred.Interface.PTBuilderT k v m)
+ Data.Trie.Pred.Interface: instance GHC.Base.Monad m => GHC.Base.Applicative (Data.Trie.Pred.Interface.PTBuilderT k v m)
+ Data.Trie.Pred.Interface: instance GHC.Base.Monad m => GHC.Base.Monad (Data.Trie.Pred.Interface.PTBuilderT k v m)
+ Data.Trie.Pred.Interface: lookup :: (Eq k, Hashable k) => [k] -> RootedPredTrie k a -> Maybe a
+ Data.Trie.Pred.Interface: match :: (Hashable k, Eq k) => [k] -> RootedPredTrie k a -> Maybe ([k], a, [k])
+ Data.Trie.Pred.Interface: matches :: (Hashable k, Eq k) => [k] -> RootedPredTrie k a -> [([k], a, [k])]
+ Data.Trie.Pred.Interface: newtype PTBuilderT k v m a
+ Data.Trie.Pred.Interface: nil :: PathChunks k '[]
+ Data.Trie.Pred.Interface: only :: k -> PathChunk k Nothing
+ Data.Trie.Pred.Interface: pred :: k -> (k -> Maybe r) -> PathChunk k (Just r)
+ Data.Trie.Pred.Interface: prefix :: (Monad m, Eq k, Hashable k, cleanxs ~ CatMaybes xs, ExtrudeSoundly k cleanxs xs childContent resultContent) => PathChunks k xs -> PTBuilderT k childContent m () -> PTBuilderT k resultContent m ()
+ Data.Trie.Pred.Interface.Types: (./) :: PathChunk k mx -> PathChunks k xs -> PathChunks k (mx : xs)
+ Data.Trie.Pred.Interface.Types: class Extend eitherUrlChunk child result | eitherUrlChunk child -> result
+ Data.Trie.Pred.Interface.Types: class Extrude chunks start result | chunks start -> result
+ Data.Trie.Pred.Interface.Types: class Singleton chunks a trie | chunks a -> trie
+ Data.Trie.Pred.Interface.Types: data PathChunk k (mx :: Maybe *)
+ Data.Trie.Pred.Interface.Types: data PathChunks k (xs :: [Maybe *])
+ Data.Trie.Pred.Interface.Types: extend :: Extend eitherUrlChunk child result => eitherUrlChunk -> child -> result
+ Data.Trie.Pred.Interface.Types: extrude :: Extrude chunks start result => chunks -> start -> result
+ Data.Trie.Pred.Interface.Types: instance (Data.Trie.Pred.Interface.Types.Extrude (Data.Trie.Pred.Interface.Types.PathChunks k xs) trie0 trie1, Data.Trie.Pred.Interface.Types.Extend (Data.Trie.Pred.Interface.Types.PathChunk k x) trie1 trie2) => Data.Trie.Pred.Interface.Types.Extrude (Data.Trie.Pred.Interface.Types.PathChunks k (x : xs)) trie0 trie2
+ Data.Trie.Pred.Interface.Types: instance (Data.Trie.Pred.Interface.Types.Singleton (Data.Trie.Pred.Interface.Types.PathChunks k xs) new trie0, Data.Trie.Pred.Interface.Types.Extend (Data.Trie.Pred.Interface.Types.PathChunk k x) trie0 trie1) => Data.Trie.Pred.Interface.Types.Singleton (Data.Trie.Pred.Interface.Types.PathChunks k (x : xs)) new trie1
+ Data.Trie.Pred.Interface.Types: instance (GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => Data.Trie.Pred.Interface.Types.Extend (Data.Trie.Pred.Interface.Types.PathChunk k 'GHC.Base.Nothing) (Data.Trie.Pred.Base.RootedPredTrie k a) (Data.Trie.Pred.Base.RootedPredTrie k a)
+ Data.Trie.Pred.Interface.Types: instance (GHC.Classes.Eq k, Data.Hashable.Class.Hashable k) => Data.Trie.Pred.Interface.Types.Extend (Data.Trie.Pred.Interface.Types.PathChunk k ('GHC.Base.Just r)) (Data.Trie.Pred.Base.RootedPredTrie k (r -> a)) (Data.Trie.Pred.Base.RootedPredTrie k a)
+ Data.Trie.Pred.Interface.Types: instance Data.String.IsString k => Data.String.IsString (Data.Trie.Pred.Interface.Types.PathChunk k 'GHC.Base.Nothing)
+ Data.Trie.Pred.Interface.Types: instance Data.Trie.Pred.Interface.Types.Extrude (Data.Trie.Pred.Interface.Types.PathChunks k '[]) (Data.Trie.Pred.Base.RootedPredTrie k a) (Data.Trie.Pred.Base.RootedPredTrie k a)
+ Data.Trie.Pred.Interface.Types: instance Data.Trie.Pred.Interface.Types.Singleton (Data.Trie.Pred.Interface.Types.PathChunks k '[]) a (Data.Trie.Pred.Base.RootedPredTrie k a)
+ Data.Trie.Pred.Interface.Types: nil :: PathChunks k '[]
+ Data.Trie.Pred.Interface.Types: only :: k -> PathChunk k Nothing
+ Data.Trie.Pred.Interface.Types: pred :: k -> (k -> Maybe r) -> PathChunk k (Just r)
+ Data.Trie.Pred.Interface.Types: singleton :: Singleton chunks a trie => chunks -> a -> trie
+ Data.Trie.Pred.Interface.Types: type ExtrudeSoundly k cleanxs xs c r = (cleanxs ~ CatMaybes xs, ArityTypeListIso c cleanxs r, Extrude (PathChunks k xs) (RootedPredTrie k c) (RootedPredTrie k r))

Files

bench/Bench.hs view
@@ -6,8 +6,8 @@   import Prelude hiding (lookup)-import           Data.Trie.Pred-import           Data.Trie.Pred.Step (PredStep (..), PredSteps (..))+import           Data.Trie.Pred.Base+import           Data.Trie.Pred.Base.Step (PredStep (..), PredSteps (..)) import           Data.Trie.Class import           Data.Trie.HashMap (HashMapStep (..), HashMapChildren (..)) import qualified Data.HashMap.Lazy as HM
pred-trie.cabal view
@@ -1,5 +1,5 @@ Name:                   pred-trie-Version:                0.4.1+Version:                0.5.0 Author:                 Athan Clark <athan.clark@gmail.com> Maintainer:             Athan Clark <athan.clark@gmail.com> License:                BSD3@@ -15,13 +15,16 @@   HS-Source-Dirs:       src   GHC-Options:          -Wall   Exposed-Modules:      Data.Trie.Pred-                        Data.Trie.Pred.Step+                        Data.Trie.Pred.Base+                        Data.Trie.Pred.Base.Step+                        Data.Trie.Pred.Interface+                        Data.Trie.Pred.Interface.Types   Build-Depends:        base >= 4.8 && < 5                       , composition-extra >= 2.0.0                       , hashable                       , mtl+                      , poly-arity >= 0.0.7                       , semigroups-                      , text                       , tries >= 0.0.4                       , unordered-containers                       , QuickCheck@@ -35,7 +38,10 @@   Main-Is:              Spec.hs   Other-Modules:        Data.Trie.PredSpec                         Data.Trie.Pred-                        Data.Trie.Pred.Step+                        Data.Trie.Pred.Base+                        Data.Trie.Pred.Base.Step+                        Data.Trie.Pred.Interface+                        Data.Trie.Pred.Interface.Types   Build-Depends:        base                       , attoparsec                       , composition-extra@@ -43,6 +49,7 @@                       , errors                       , hashable                       , mtl+                      , poly-arity                       , semigroups                       , text                       , tries@@ -58,20 +65,24 @@   Default-Language:     Haskell2010   Main-Is:              Bench.hs   Other-Modules:        Data.Trie.Pred-                        Data.Trie.Pred.Step+                        Data.Trie.Pred.Base+                        Data.Trie.Pred.Base.Step+                        Data.Trie.Pred.Interface+                        Data.Trie.Pred.Interface.Types   HS-Source-Dirs:       bench                       , src   Ghc-Options:          -Wall -threaded   Build-Depends:        base+                      , attoparsec                       , composition-extra                       , deepseq                       , hashable                       , mtl+                      , poly-arity                       , semigroups+                      , text                       , tries                       , unordered-containers-                      , attoparsec-                      , text                       , QuickCheck                       , sets                       , criterion
src/Data/Trie/Pred.hs view
@@ -1,226 +1,5 @@-{-# LANGUAGE-    ExistentialQuantification-  , FlexibleContexts-  , FlexibleInstances-  , MultiParamTypeClasses-  , DeriveFunctor-  , DeriveGeneric-  , DeriveDataTypeable-  , TupleSections-  , BangPatterns-  #-}--{- |-Module      : Data.Trie.Pred-Copyright   : (c) 2015 Athan Clark--License     : BSD-3-Maintainer  : athan.clark@gmail.com-Stability   : experimental-Portability : GHC--A "predicative" trie is a lookup table where you can use /predicates/-as a method to match a query path, where success is also enriched with /any/-auxiliary data. This library allows you to match a path-chunk (if you consider-a query to the different levels of the tree as a /list/) with a Boolean predicate,-augmented with existentially quantified data. This lets us use parsers, regular-expressions, and other functions that can be turned into the form of:--> forall a. p -> Maybe a--However, because the communicated data is existentially quantified, we __cannot__-revisit a definition - we cannot @update@ a predicative node, or change any of-its children. The current version of this library forces you to use 'PredTrie'-and 'RootedPredTrie' directly (i.e. the data constructors) to build your trie-manually.--This isn't the actual code, but it's a general idea for how you could build a-trie. We build a "tagged" <https://en.wikipedia.org/wiki/Rose_tree rose-tree>,-where each node has either a literal name (and is a singleton of the @k@ type in our-lookup path) or a predicate to consider the current node or its children as the target.-You could imagine a "step" of the trie structure as something like this:--> data PredTrie k a->   = Nil->   | Lit->       { litTag       :: k->       , litResult    :: Maybe a->       , litChildren  :: Maybe (PredTrie k a)->       }->   | forall t. Pred->       { predMatch    :: k -> Maybe t->       , predResult   :: Maybe (t -> a)->       , predChildren :: Maybe (PredTrie k a)->       }--Notice how in the @Pred@ constructor, we first /create/ the @t@ data in @predMatch@,-then /consume/ it in @predResult@. We make a tree out of steps by recursing over the-steps.--This isn't how it's actually represented, unfortunately. There will be a-monadic interface in the next version.--}--module Data.Trie.Pred where--import Prelude hiding (lookup)-import Data.Trie.Pred.Step-import Data.Trie.Class-import qualified Data.Trie.HashMap as HT-import qualified Data.HashMap.Lazy as HM-import Data.List.NonEmpty (NonEmpty (..))-import qualified Data.List.NonEmpty as NE--import Data.Typeable-import Data.Functor.Syntax-import Data.Monoid-import Data.Maybe (fromMaybe)-import Data.Hashable-import Test.QuickCheck------ * Predicated Trie--data PredTrie k a = PredTrie-  { predLits  :: !(HT.HashMapStep PredTrie k a) -- ^ a /literal/ step-  , predPreds :: !(PredSteps PredTrie k a)      -- ^ a /predicative/ step-  } deriving (Show, Functor, Typeable)--instance ( Arbitrary k-         , Arbitrary a-         , Eq k-         , Hashable k-         ) => Arbitrary (PredTrie k a) where-  arbitrary = (flip PredTrie $ PredSteps []) <$> arbitrary--instance ( Hashable k-         , Eq k-         ) => Trie NonEmpty k PredTrie where-  lookup ts (PredTrie ls ps) =-    getFirst $ (First $! lookup ts ls) <> First (lookup ts ps)-  delete ts (PredTrie ls ps) = PredTrie (delete ts ls) (delete ts ps)-  insert ts x (PredTrie ls ps) = PredTrie (HT.insert ts x ls) ps -- can only insert literals--instance ( Hashable k-         , Eq k-         ) => Monoid (PredTrie k a) where-  mempty = PredTrie mempty mempty-  mappend (PredTrie ls1 ps1) (PredTrie ls2 ps2) =-    (PredTrie $! ls1 <> ls2) $! ps1 <> ps2--emptyPT :: PredTrie k a-emptyPT = PredTrie HT.empty (PredSteps [])----- subtrie :: Ord s => NonEmpty s -> PredTrie s a -> PredTrie s a--- subtrie (t:|ts) (PredTrie (MapTrie (MapStep ls)) ps)---   | null ts = getFirst $ First (lookup ts ls)---- | Find the nearest parent node of the requested query, while returning--- the split of the string that was matched, and what wasn't.-matchPT :: ( Hashable k-           , Eq k-           ) => NonEmpty k -> PredTrie k a -> Maybe (NonEmpty k, a, [k])-matchPT (t:|ts) (PredTrie ls (PredSteps ps)) = getFirst $-  First (goLit ls) <> foldMap (First . goPred) ps-  where-    goLit (HT.HashMapStep xs) = do-      (HT.HashMapChildren mx mxs) <- HM.lookup t xs-      let mFoundHere = (t:|[],, []) <$> mx-      if null ts-      then mFoundHere-      else getFirst $ First (do (pre,y,suff) <- matchPT (NE.fromList ts) =<< mxs-                                return (t:|NE.toList pre, y, suff))-                   <> First mFoundHere--    goPred (PredStep _ p mx xs) = do-      r <- p t-      let mFoundHere = do x <- mx <$~> r-                          return (t:|[], x, [])-      if null ts-      then mFoundHere-      else getFirst $ First (do (pre,y,suff) <- matchPT (NE.fromList ts) xs-                                return (t:|NE.toList pre, y r, suff))-                   <> First mFoundHere---matchesPT :: ( Hashable k-             , Eq k-             ) => NonEmpty k -> PredTrie k a -> [(NonEmpty k, a, [k])]-matchesPT (t:|ts) (PredTrie ls (PredSteps ps)) =-  fromMaybe [] $ getFirst $ First (goLit ls) <> foldMap (First . goPred) ps-  where-    goLit (HT.HashMapStep xs) = do-      (HT.HashMapChildren mx mxs) <- HM.lookup t xs-      let mFoundHere = do x <- mx-                          return [(t:|[],x,ts)]-          prependAncestry (pre,x,suff) = (t:| NE.toList pre,x,suff)-      if null ts-      then mFoundHere-      else do foundHere <- mFoundHere-              let rs = fromMaybe [] $! matchesPT (NE.fromList ts) <$> mxs-              return $! foundHere ++ (prependAncestry <$> rs)--    goPred (PredStep _ p mx xs) = do-      r <- p t-      let mFoundHere = do x <- mx <$~> r-                          return [(t:|[],x,ts)]-          prependAncestryAndApply (pre,x,suff) = (t:| NE.toList pre,x r,suff)-      if null ts-      then mFoundHere-      else do foundHere <- mFoundHere-              let rs = matchesPT (NE.fromList ts) xs-              return $! foundHere ++ (prependAncestryAndApply <$> rs)---- * Rooted Predicative Trie--data RootedPredTrie k a = RootedPredTrie-  { rootedBase :: !(Maybe a)      -- ^ The "root" node - the path at @[]@-  , rootedSub  :: !(PredTrie k a) -- ^ The actual predicative trie-  } deriving (Show, Functor, Typeable)---instance ( Hashable k-         , Eq k-         ) => Trie [] k RootedPredTrie where-  lookup [] (RootedPredTrie mx _) = mx-  lookup ts (RootedPredTrie _ xs) = lookup (NE.fromList ts) xs--  delete [] (RootedPredTrie _ xs)  = RootedPredTrie Nothing xs-  delete ts (RootedPredTrie mx xs) = RootedPredTrie mx $! delete (NE.fromList ts) xs--  insert [] x (RootedPredTrie _ xs)  = RootedPredTrie (Just x) xs-  insert ts x (RootedPredTrie mx xs) = RootedPredTrie mx $! insert (NE.fromList ts) x xs---instance ( Hashable k-         , Eq k-         ) => Monoid (RootedPredTrie k a) where-  mempty = emptyRPT-  mappend (RootedPredTrie mx xs) (RootedPredTrie my ys) = RootedPredTrie-    (getLast $! Last mx <> Last my) $! xs <> ys---emptyRPT :: RootedPredTrie k a-emptyRPT = RootedPredTrie Nothing emptyPT--matchRPT :: ( Hashable k-            , Eq k-            ) => [k] -> RootedPredTrie k a -> Maybe ([k], a, [k])-matchRPT [] (RootedPredTrie mx _)  = ([],,[]) <$> mx-matchRPT ts (RootedPredTrie mx xs) = getFirst $-  First mFoundThere <> First (([],,[]) <$> mx)-  where-    mFoundThere = do (pre,x,suff) <- matchPT (NE.fromList ts) xs-                     pure (NE.toList pre,x,suff)+module Data.Trie.Pred+  ( module Data.Trie.Pred.Interface+  ) where -matchesRPT :: ( Hashable k-              , Eq k-              ) => [k] -> RootedPredTrie k a -> [([k], a, [k])]-matchesRPT [] (RootedPredTrie mx _)  = fromMaybe [] $ (\x -> [([],x,[])]) <$> mx-matchesRPT ts (RootedPredTrie mx xs) =-  (foundHere ++) $! fmap allowRoot  (matchesPT (NE.fromList ts) xs)-  where-    foundHere = fromMaybe [] $! (\x -> [([],x,[])]) <$> mx-    allowRoot (pre,x,suff) = (NE.toList pre,x,suff)+import Data.Trie.Pred.Interface
+ src/Data/Trie/Pred/Base.hs view
@@ -0,0 +1,225 @@+{-# LANGUAGE+    ExistentialQuantification+  , FlexibleContexts+  , FlexibleInstances+  , MultiParamTypeClasses+  , DeriveFunctor+  , DeriveDataTypeable+  , TupleSections+  #-}++{- |+Module      : Data.Trie.Pred.Base+Copyright   : (c) 2015 Athan Clark++License     : BSD-3+Maintainer  : athan.clark@gmail.com+Stability   : experimental+Portability : GHC++A "predicative" trie is a lookup table where you can use /predicates/+as a method to match a query path, where success is also enriched with /any/+auxiliary data. This library allows you to match a path-chunk (if you consider+a query to the different levels of the tree as a /list/) with a Boolean predicate,+augmented with existentially quantified data. This lets us use parsers, regular+expressions, and other functions that can be turned into the form of:++> forall a. p -> Maybe a++However, because the communicated data is existentially quantified, we __cannot__+revisit a definition - we cannot @update@ a predicative node, or change any of+its children. The current version of this library forces you to use 'PredTrie'+and 'RootedPredTrie' directly (i.e. the data constructors) to build your trie+manually.++This isn't the actual code, but it's a general idea for how you could build a+trie. We build a "tagged" <https://en.wikipedia.org/wiki/Rose_tree rose-tree>,+where each node has either a literal name (and is a singleton of the @k@ type in our+lookup path) or a predicate to consider the current node or its children as the target.+You could imagine a "step" of the trie structure as something like this:++> data PredTrie k a+>   = Nil+>   | Lit+>       { litTag       :: k+>       , litResult    :: Maybe a+>       , litChildren  :: Maybe (PredTrie k a)+>       }+>   | forall t. Pred+>       { predMatch    :: k -> Maybe t+>       , predResult   :: Maybe (t -> a)+>       , predChildren :: Maybe (PredTrie k a)+>       }++Notice how in the @Pred@ constructor, we first /create/ the @t@ data in @predMatch@,+then /consume/ it in @predResult@. We make a tree out of steps by recursing over the+steps.++This isn't how it's actually represented internally, but serves to help see the+representation. If you want to build tries+and perform lookups casually, please see the "Data.Trie.Pred.Interface" module.+-}++module Data.Trie.Pred.Base where++import Prelude hiding (lookup)+import Data.Trie.Pred.Base.Step+import Data.Trie.Class+import qualified Data.Trie.HashMap as HT+import qualified Data.HashMap.Lazy as HM+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NE++import Data.Typeable+import Data.Functor.Syntax+import Data.Monoid+import Data.Maybe (fromMaybe)+import Data.Hashable+import Test.QuickCheck++++-- * Predicated Trie++data PredTrie k a = PredTrie+  { predLits  :: !(HT.HashMapStep PredTrie k a) -- ^ a /literal/ step+  , predPreds :: !(PredSteps k PredTrie k a)      -- ^ a /predicative/ step+  } deriving (Show, Functor, Typeable)++instance ( Arbitrary k+         , Arbitrary a+         , Eq k+         , Hashable k+         ) => Arbitrary (PredTrie k a) where+  arbitrary = flip PredTrie (PredSteps []) <$> arbitrary++instance ( Hashable k+         , Eq k+         ) => Trie NonEmpty k PredTrie where+  lookup ts (PredTrie ls ps) =+    getFirst $ (First $! lookup ts ls) <> First (lookup ts ps)+  delete ts (PredTrie ls ps) = PredTrie (delete ts ls) (delete ts ps)+  insert ts x (PredTrie ls ps) = PredTrie (HT.insert ts x ls) ps -- can only insert literals++instance ( Hashable k+         , Eq k+         ) => Monoid (PredTrie k a) where+  mempty = PredTrie mempty mempty+  mappend (PredTrie ls1 ps1) (PredTrie ls2 ps2) =+    (PredTrie $! ls1 <> ls2) $! ps1 <> ps2++emptyPT :: PredTrie k a+emptyPT = PredTrie HT.empty (PredSteps [])+++-- subtrie :: Ord s => NonEmpty s -> PredTrie s a -> PredTrie s a+-- subtrie (t:|ts) (PredTrie (MapTrie (MapStep ls)) ps)+--   | null ts = getFirst $ First (lookup ts ls)++-- | Find the nearest parent node of the requested query, while returning+-- the split of the string that was matched, and what wasn't.+matchPT :: ( Hashable k+           , Eq k+           ) => NonEmpty k -> PredTrie k a -> Maybe (NonEmpty k, a, [k])+matchPT (t:|ts) (PredTrie ls (PredSteps ps)) = getFirst $+  First (goLit ls) <> foldMap (First . goPred) ps+  where+    goLit (HT.HashMapStep xs) = do+      (HT.HashMapChildren mx mxs) <- HM.lookup t xs+      let mFoundHere = (t:|[],, []) <$> mx+      if null ts+      then mFoundHere+      else getFirst $ First (do (pre,y,suff) <- matchPT (NE.fromList ts) =<< mxs+                                return (t:|NE.toList pre, y, suff))+                   <> First mFoundHere++    goPred (PredStep _ p mx xs) = do+      r <- p t+      let mFoundHere = do x <- mx <$~> r+                          return (t:|[], x, [])+      if null ts+      then mFoundHere+      else getFirst $ First (do (pre,y,suff) <- matchPT (NE.fromList ts) xs+                                return (t:|NE.toList pre, y r, suff))+                   <> First mFoundHere+++matchesPT :: ( Hashable k+             , Eq k+             ) => NonEmpty k -> PredTrie k a -> [(NonEmpty k, a, [k])]+matchesPT (t:|ts) (PredTrie ls (PredSteps ps)) =+  fromMaybe [] $ getFirst $ First (goLit ls) <> foldMap (First . goPred) ps+  where+    goLit (HT.HashMapStep xs) = do+      (HT.HashMapChildren mx mxs) <- HM.lookup t xs+      let mFoundHere = do x <- mx+                          return [(t:|[],x,ts)]+          prependAncestry (pre,x,suff) = (t:| NE.toList pre,x,suff)+      if null ts+      then mFoundHere+      else do foundHere <- mFoundHere+              let rs = fromMaybe [] $! matchesPT (NE.fromList ts) <$> mxs+              return $! foundHere ++ (prependAncestry <$> rs)++    goPred (PredStep _ p mx xs) = do+      r <- p t+      let mFoundHere = do x <- mx <$~> r+                          return [(t:|[],x,ts)]+          prependAncestryAndApply (pre,x,suff) = (t:| NE.toList pre,x r,suff)+      if null ts+      then mFoundHere+      else do foundHere <- mFoundHere+              let rs = matchesPT (NE.fromList ts) xs+              return $! foundHere ++ (prependAncestryAndApply <$> rs)++-- * Rooted Predicative Trie++data RootedPredTrie k a = RootedPredTrie+  { rootedBase :: !(Maybe a)      -- ^ The "root" node - the path at @[]@+  , rootedSub  :: !(PredTrie k a) -- ^ The actual predicative trie+  } deriving (Show, Functor, Typeable)+++instance ( Hashable k+         , Eq k+         ) => Trie [] k RootedPredTrie where+  lookup [] (RootedPredTrie mx _) = mx+  lookup ts (RootedPredTrie _ xs) = lookup (NE.fromList ts) xs++  delete [] (RootedPredTrie _ xs)  = RootedPredTrie Nothing xs+  delete ts (RootedPredTrie mx xs) = RootedPredTrie mx $! delete (NE.fromList ts) xs++  insert [] x (RootedPredTrie _ xs)  = RootedPredTrie (Just x) xs+  insert ts x (RootedPredTrie mx xs) = RootedPredTrie mx $! insert (NE.fromList ts) x xs+++instance ( Hashable k+         , Eq k+         ) => Monoid (RootedPredTrie k a) where+  mempty = emptyRPT+  mappend (RootedPredTrie mx xs) (RootedPredTrie my ys) = RootedPredTrie+    (getLast $! Last mx <> Last my) $! xs <> ys+++emptyRPT :: RootedPredTrie k a+emptyRPT = RootedPredTrie Nothing emptyPT++matchRPT :: ( Hashable k+            , Eq k+            ) => [k] -> RootedPredTrie k a -> Maybe ([k], a, [k])+matchRPT [] (RootedPredTrie mx _)  = ([],,[]) <$> mx+matchRPT ts (RootedPredTrie mx xs) = getFirst $+  First mFoundThere <> First (([],,[]) <$> mx)+  where+    mFoundThere = do (pre,x,suff) <- matchPT (NE.fromList ts) xs+                     pure (NE.toList pre,x,suff)++matchesRPT :: ( Hashable k+              , Eq k+              ) => [k] -> RootedPredTrie k a -> [([k], a, [k])]+matchesRPT [] (RootedPredTrie mx _)  = fromMaybe [] $ (\x -> [([],x,[])]) <$> mx+matchesRPT ts (RootedPredTrie mx xs) =+  (foundHere ++) $! fmap allowRoot  (matchesPT (NE.fromList ts) xs)+  where+    foundHere = fromMaybe [] $! (\x -> [([],x,[])]) <$> mx+    allowRoot (pre,x,suff) = (NE.toList pre,x,suff)
+ src/Data/Trie/Pred/Base/Step.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE+    ExistentialQuantification+  , FlexibleContexts+  , FlexibleInstances+  , MultiParamTypeClasses+  , DeriveFunctor+  , DeriveDataTypeable+  #-}++{- |+Module      : Data.Trie.Pred.Base.Step+Copyright   : (c) 2015 Athan Clark++License     : BSD-3+Maintainer  : athan.clark@gmail.com+Stability   : experimental+Portability : GHC+-}++module Data.Trie.Pred.Base.Step where++import Prelude hiding (lookup)+import Data.Trie.Class+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NE++import Data.Typeable+import Data.Functor.Syntax+import Data.Monoid+++-- * Single Predicated Step++data PredStep k c s a = forall r. PredStep+  { -- | Unique identifier for the predicate - used for combination+    predTag  :: !k+  , -- | The predicate, existentially quantified in the successful result @r@+    predPred :: !(s -> Maybe r) +  , -- | The result function, capturing the quantified result @r@ and turning+    --   it into a top-level variable @a@.+    predData :: !(Maybe (r -> a))+  , -- | Any sub-trie must have __all__ results preceeded in arity with+    --   the result at this step.+    predSub  :: !(c s (r -> a))+  } deriving (Typeable)++instance ( Show s+         , Show k+         ) => Show (PredStep k c s a) where+  show (PredStep t _ _ _) = "PredStep {predTag=" ++ show t ++ ", ...}"++instance Functor (c s) => Functor (PredStep k c s) where+  fmap f (PredStep i p mx xs) = (PredStep i p $! f <.$> mx) $! f <.$> xs++-- | Lookup and delete only - can't arbitrarilly construct a predicated trie.+instance Trie NonEmpty s c => Trie NonEmpty s (PredStep k c) where+  lookup (t:|ts) (PredStep _ p mx xs) = do+    r <- p t+    if null ts then mx <$~> r+               else lookup (NE.fromList ts) xs <$~> r+  delete (t:|ts) xss@(PredStep i p mx xs) =+    maybe xss+      (const $ if null ts+               then PredStep i p Nothing xs+               else PredStep i p mx $! delete (NE.fromList ts) xs)+      (p t)++singletonPred :: Monoid (c s (r -> a)) => k -> (s -> Maybe r) -> (r -> a) -> PredStep k c s a+singletonPred i p x = PredStep i p (Just x) mempty+++-- * Adjacent Predicated Steps++-- | Adjacent steps+newtype PredSteps k c s a = PredSteps+  { unPredSteps :: [PredStep k c s a]+  } deriving (Show, Functor, Typeable)++-- | Lookup and delete only - can't arbitrarilly construct a predicated trie.+instance Trie NonEmpty s c => Trie NonEmpty s (PredSteps k c) where+  lookup ts (PredSteps ps) = getFirst $! foldMap (First . lookup ts) ps+  delete ts (PredSteps ps) = PredSteps $! fmap (delete ts) ps++instance ( Eq s+         , Eq k+         ) => Monoid (PredSteps k c s a) where+  mempty  = PredSteps []+  mappend = unionPred++-- | @Last@-style instance+unionPred :: ( Eq k+             ) => PredSteps k c s a+               -> PredSteps k c s a+               -> PredSteps k c s a+unionPred (PredSteps (xss@(PredStep i _ _ _):pxs)) (PredSteps (yss@(PredStep j _ _ _):pys))+  | i == j    = PredSteps $ yss :       (unPredSteps $! unionPred (PredSteps pxs) (PredSteps pys))+  | otherwise = PredSteps $ xss : yss : (unPredSteps $! unionPred (PredSteps pxs) (PredSteps pys))+unionPred x (PredSteps []) = x+unionPred (PredSteps []) y = y
+ src/Data/Trie/Pred/Interface.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE+    GeneralizedNewtypeDeriving+  , MultiParamTypeClasses+  , DeriveFunctor+  , BangPatterns+  , FlexibleContexts+  , TypeFamilies+  #-}++{- |+Module      : Data.Trie.Pred.Interface+Copyright   : (c) 2015 Athan Clark++License     : BSD-style+Maintainer  : athan.clark@gmail.com+Stability   : experimental+Portability : GHC++This module defines a "builder" monad, which aides in the process of building+a trie. It's a monad transformer, so you can use it alongside whichever+context you're already working in.++> myBuilder :: ( Eq k+>              , Hashable k+>              , MonadIO m+>              ) => PTBuilder String Int m ()+> myBuilder = do+>   insertHere 0+>   insert ("some" ./ "path" ./ nil) 1+>   insert ("some" ./ pred "pred-chunk" upperPred ./ nil) 2+>   prefix ("some") $ do+>     insert ("thing" ./ nil) 3+>     insert ("else" ./ nil) 4+>     data <- liftIO (doSomething)+>     insert ("another" ./ "thing" ./ nil) data+>   where+>     uppderPred :: String -> Maybe String+>     uppderPred s | all isUpperCase s = Just s+>                  | otherwise         = Nothing+>++Then we can get our trie to perform lookups by executing the monad:++> main :: IO ()+> main = do+>   trie <- execPTBuilderT myBuilder+>   print (lookup ["foo", "bar", "baz"] trie)++-}++module Data.Trie.Pred.Interface+  ( -- * Construction+    -- ** Builder Monad+    PTBuilderT (..)+  , execPTBuilderT+  , -- ** Combinators+    insert+  , insertHere+  , prefix+  , -- ** Specifying Paths+    only+  , pred+  , (./)+  , nil+  , -- * Query+    lookup+  , match+  , matches+  , -- * Delete+    delete+  , -- * Types+    RootedPredTrie+  , PathChunks+  , PathChunk+  ) where++import Prelude hiding (lookup, pred)+import Data.Trie.Pred.Base+import Data.Trie.Pred.Interface.Types+import Data.Function.Poly+import qualified Data.Trie.Class as TC++import Data.Hashable+import Data.Monoid+import Control.Monad.State+import Control.Monad.Writer+++-- * Building Tries++newtype PTBuilderT k v m a = PTBuilderT+  { runPTBuilderT :: StateT (RootedPredTrie k v) m a+  } deriving (Functor, Applicative, Monad, MonadTrans, MonadState (RootedPredTrie k v))++instance ( Monad m+         , Eq k+         , Hashable k+         ) => MonadWriter (RootedPredTrie k v) (PTBuilderT k v m) where+  tell x = modify' (x <>)+  listen x = do+    x' <- x+    w <- get+    return (x', w)+  pass x = do+    (x', f) <- x+    modify' f+    return x'+++execPTBuilderT :: ( Monad m+                  , Eq k+                  , Hashable k+                  ) => PTBuilderT k v m a -> m (RootedPredTrie k v)+execPTBuilderT = flip execStateT mempty . runPTBuilderT+++-- * Combinators++insert :: ( Monad m+          , Eq k+          , Hashable k+          , Singleton (PathChunks k xs)+              childContent+              (RootedPredTrie k resultContent)+          , cleanxs ~ CatMaybes xs+          , ArityTypeListIso childContent cleanxs resultContent+          ) => PathChunks k xs+            -> childContent+            -> PTBuilderT k resultContent m ()+insert !ts !vl =+  modify' ((singleton ts vl) <>)+++insertHere :: ( Monad m+              , Eq k+              , Hashable k+              ) => v+                -> PTBuilderT k v m ()+insertHere = insert nil+++prefix :: ( Monad m+          , Eq k+          , Hashable k+          , cleanxs ~ CatMaybes xs+          , ExtrudeSoundly k cleanxs xs childContent resultContent+          ) => PathChunks k xs+            -> PTBuilderT k childContent  m ()+            -> PTBuilderT k resultContent m ()+prefix !ts cs = do+  trie <- lift (execPTBuilderT cs)+  modify' ((extrude ts trie) <>)+++lookup :: ( Eq k+          , Hashable k+          ) => [k] -> RootedPredTrie k a -> Maybe a+lookup = TC.lookup++delete :: ( Eq k+          , Hashable k+          ) => [k] -> RootedPredTrie k a -> RootedPredTrie k a+delete = TC.delete++match :: ( Hashable k+         , Eq k+         ) => [k] -> RootedPredTrie k a -> Maybe ([k], a, [k])+match = matchRPT+++matches :: ( Hashable k+           , Eq k+           ) => [k] -> RootedPredTrie k a -> [([k], a, [k])]+matches = matchesRPT
+ src/Data/Trie/Pred/Interface/Types.hs view
@@ -0,0 +1,164 @@+{-# LANGUAGE+    GADTs+  , TypeOperators+  , TypeFamilies+  , KindSignatures+  , DataKinds+  , RankNTypes+  , FlexibleInstances+  , FlexibleContexts+  , UndecidableInstances+  , MultiParamTypeClasses+  , FunctionalDependencies+  , ConstraintKinds+  , BangPatterns+  , OverloadedStrings+  #-}+++{- |+Module      : Data.Trie.Pred.Interface.Types+Copyright   : (c) 2015 Athan Clark++License     : BSD-style+Maintainer  : athan.clark@gmail.com+Stability   : experimental+Portability : GHC+-}++module Data.Trie.Pred.Interface.Types+  ( -- * Heterogenous Construction+    Singleton (..)+  , Extend (..)+  , Extrude (..)+  , ExtrudeSoundly+  , CatMaybes+  , -- * Path Construction+    only+  , pred+  , (./)+  , nil+  , -- * Path Types+    PathChunk+  , PathChunks+  ) where+++import Prelude hiding (pred)+import           Data.Trie.Pred.Base+import           Data.Trie.Pred.Base.Step+import qualified Data.Trie.HashMap as HT+import qualified Data.HashMap.Lazy as HM+import Data.Hashable+import Data.Function.Poly++import Data.String (IsString (..))+++-- * Classes++-- | Convenience type-level function for removing 'Nothing's from a type list.+type family CatMaybes (xs :: [Maybe *]) :: [*] where+  CatMaybes '[]               = '[]+  CatMaybes ('Nothing  ': xs) =      CatMaybes xs+  CatMaybes (('Just x) ': xs) = x ': CatMaybes xs++-- | Creates a string of nodes - a trie with a width of 1.+class Singleton chunks a trie | chunks a -> trie where+  singleton :: chunks -> a -> trie++-- Basis+instance Singleton (PathChunks k '[]) a (RootedPredTrie k a) where+  singleton Nil r = RootedPredTrie (Just r) emptyPT++-- Successor+instance ( Singleton (PathChunks k xs) new trie0+         , Extend (PathChunk k x) trie0 trie1+         ) => Singleton (PathChunks k (x ': xs)) new trie1 where+  singleton (Cons u us) r = extend u $! singleton us r+++-- | Turn a list of tries (@Rooted@) into a node with those children+class Extend eitherUrlChunk child result | eitherUrlChunk child -> result where+  extend :: eitherUrlChunk -> child -> result++-- | Literal case+instance ( Eq k+         , Hashable k+         ) => Extend (PathChunk k 'Nothing) (RootedPredTrie k a) (RootedPredTrie k a) where+  extend (Lit t) (RootedPredTrie mx xs) = RootedPredTrie Nothing $+    PredTrie (HT.HashMapStep $! HM.singleton t (HT.HashMapChildren mx $ Just xs)) mempty++-- | Existentially quantified case+instance ( Eq k+         , Hashable k+         ) => Extend (PathChunk k ('Just r)) (RootedPredTrie k (r -> a)) (RootedPredTrie k a) where+  extend (Pred i q) (RootedPredTrie mx xs) = RootedPredTrie Nothing $+    PredTrie mempty (PredSteps [PredStep i q mx xs])+++-- | @FoldR Extend start chunks ~ result@+class Extrude chunks start result | chunks start -> result where+  extrude :: chunks -> start -> result++-- Basis+instance Extrude (PathChunks k '[]) (RootedPredTrie k a) (RootedPredTrie k a) where+  extrude Nil r = r++-- Successor+instance ( Extrude (PathChunks k xs) trie0 trie1+         , Extend  (PathChunk k x)   trie1 trie2+         ) => Extrude (PathChunks k (x ': xs)) trie0 trie2 where+  extrude (Cons u us) r = extend u $! extrude us r+++-- | A simple proof showing that the list version and function version are+--   interchangable.+type ExtrudeSoundly k cleanxs xs c r =+  ( cleanxs ~ CatMaybes xs+  , ArityTypeListIso c cleanxs r+  , Extrude (PathChunks k xs)+      (RootedPredTrie k c)+      (RootedPredTrie k r)+  )++-- * Query Types++-- | Match a literal key+only :: k -> PathChunk k 'Nothing+only = Lit++-- | Match with a predicate against the url chunk directly.+pred :: k -> (k -> Maybe r) -> PathChunk k ('Just r)+pred = Pred+++-- | Constrained to AttoParsec, Regex-Compat and T.Text+data PathChunk k (mx :: Maybe *) where+  Lit  :: { litChunk :: !k+          } -> PathChunk k 'Nothing+  Pred :: { predTag  :: !k+          , predPred :: !(k -> Maybe r)+          } -> PathChunk k ('Just r)++-- | Use raw strings instead of prepending @l@+instance IsString k => IsString (PathChunk k 'Nothing) where+  fromString = Lit . fromString++-- | Container when defining route paths+data PathChunks k (xs :: [Maybe *]) where+  Cons :: PathChunk k mx+       -> PathChunks k xs+       -> PathChunks k (mx ': xs)+  Nil  :: PathChunks k '[]+++-- | The cons-cell for building a query path.+(./) :: PathChunk k mx -> PathChunks k xs -> PathChunks k (mx ': xs)+(./) = Cons++infixr 9 ./++-- | The basis, equivalent to @[]@+nil :: PathChunks k '[]+nil = Nil
− src/Data/Trie/Pred/Step.hs
@@ -1,91 +0,0 @@-{-# LANGUAGE-    ExistentialQuantification-  , FlexibleContexts-  , FlexibleInstances-  , MultiParamTypeClasses-  , DeriveFunctor-  , DeriveGeneric-  , DeriveDataTypeable-  , BangPatterns-  #-}--{- |-Module      : Data.Trie.Pred-Copyright   : (c) 2015 Athan Clark--License     : BSD-3-Maintainer  : athan.clark@gmail.com-Stability   : experimental-Portability : GHC--}--module Data.Trie.Pred.Step where--import Prelude hiding (lookup)-import Data.Trie.Class-import Data.List.NonEmpty (NonEmpty (..))-import qualified Data.List.NonEmpty as NE-import qualified Data.Text          as T--import Data.Typeable-import Data.Functor.Syntax-import Data.Monoid----- * Single Predicated Step--data PredStep c s a = forall r. PredStep-  { predTag  :: {-# UNPACK #-} !T.Text -- ^ Unique identifier for the predicate - used for combination-  , predPred :: !(s -> Maybe r)        -- ^ The predicate, existentially quantified in the successful result @r@-  , predData :: !(Maybe (r -> a))      -- ^ The result function, capturing the quantified result @r@ and turning-                                       --   it into a top-level variable @a@.-  , predSub  :: !(c s (r -> a))        -- ^ Any sub-trie must have __all__ results preceeded in arity with-                                       --   the result at this step.-  } deriving (Typeable)--instance Show s => Show (PredStep c s a) where-  show (PredStep t _ _ _) = "PredStep {predTag=" ++ show t ++ ", ...}"--instance Functor (c s) => Functor (PredStep c s) where-  fmap f (PredStep i p mx xs) = (PredStep i p $! f <.$> mx) $! f <.$> xs---- | Lookup and delete only - can't arbitrarilly construct a predicated trie.-instance Trie NonEmpty s c => Trie NonEmpty s (PredStep c) where-  lookup (t:|ts) (PredStep _ p mx xs) = do-    r <- p t-    if null ts then mx <$~> r-               else lookup (NE.fromList ts) xs <$~> r-  delete (t:|ts) xss@(PredStep i p mx xs) =-    maybe xss-      (const $ if null ts-               then PredStep i p Nothing xs-               else PredStep i p mx $! delete (NE.fromList ts) xs)-      (p t)--singletonPred :: Monoid (c s (r -> a)) => T.Text -> (s -> Maybe r) -> (r -> a) -> PredStep c s a-singletonPred i p x = PredStep i p (Just x) mempty----- * Adjacent Predicated Steps---- | Adjacent steps-newtype PredSteps c s a = PredSteps-  { unPredSteps :: [PredStep c s a]-  } deriving (Show, Functor, Typeable)---- | Lookup and delete only - can't arbitrarilly construct a predicated trie.-instance Trie NonEmpty s c => Trie NonEmpty s (PredSteps c) where-  lookup ts (PredSteps ps) = getFirst $! foldMap (First . lookup ts) ps-  delete ts (PredSteps ps) = PredSteps $! fmap (delete ts) ps--instance Eq s => Monoid (PredSteps c s a) where-  mempty  = PredSteps []-  mappend = unionPred---- | @Last@-style instance-unionPred :: PredSteps c s a -> PredSteps c s a -> PredSteps c s a-unionPred (PredSteps (xss@(PredStep i _ _ _):pxs)) (PredSteps (yss@(PredStep j _ _ _):pys))-  | i == j    = PredSteps $ yss :       (unPredSteps $! unionPred (PredSteps pxs) (PredSteps pys))-  | otherwise = PredSteps $ xss : yss : (unPredSteps $! unionPred (PredSteps pxs) (PredSteps pys))-unionPred x (PredSteps []) = x-unionPred (PredSteps []) y = y
test/Data/Trie/PredSpec.hs view
@@ -4,8 +4,8 @@  module Data.Trie.PredSpec where -import Data.Trie.Pred-import Data.Trie.Pred.Step+import Data.Trie.Pred.Base+import Data.Trie.Pred.Base.Step import Data.Trie.Class import Data.Trie.HashMap (HashMapStep (..)) import Data.List.NonEmpty (NonEmpty (..))