module Graphics.Curves.Trie
( Trie
, empty, lookup, lookupPrefix
, toList, fromList, union, insert
, size
) where
import Prelude hiding (lookup, foldr)
import Control.Monad
import Control.Applicative hiding (empty)
import Data.Foldable hiding (toList, concatMap)
import Data.Monoid
import Data.Maybe
import Data.List hiding (lookup, foldr, union, insert)
import qualified Data.Map as Map
import Data.Map (Map)
import Test.QuickCheck
import Test.QuickCheck.Function
data Trie a b = Node (Maybe b) (Map a (Trie a b))
deriving (Functor, Foldable, Eq, Ord)
instance (Show a, Show b) => Show (Trie a b) where
show t = "[" ++ intercalate ", " (map f (toList t)) ++ "]"
where
f (ks, v) = show ks ++ " -> " ++ show v
instance (Ord a, Monoid b) => Monoid (Trie a b) where
mempty = empty
mappend (Node v m) (Node v' m') =
Node (mappend v v') (Map.unionWith mappend m m')
empty :: Trie a b
empty = Node Nothing Map.empty
lookup :: Ord a => [a] -> Trie a b -> Maybe b
lookup [] (Node v _) = v
lookup (k:ks) (Node _ t) = lookup ks =<< Map.lookup k t
lookupPrefix :: Ord a => [a] -> Trie a b -> Maybe (b, [a], [a])
lookupPrefix ks (Node v t) =
case ks of
[] -> done
k:ks -> (cons k <$> (lookupPrefix ks =<< Map.lookup k t)) `mplus` done
where
done = (,,) <$> v <*> pure [] <*> pure ks
cons k (v, ks, ks') = (v, k:ks, ks')
toList :: Trie a b -> [([a], b)]
toList (Node v t) =
[ ([], v) | Just v <- [v] ] ++
[ (k:ks, v) | (k, t) <- Map.toList t
, (ks, v) <- toList t ]
singleton :: [a] -> b -> Trie a b
singleton [] v = Node (Just v) Map.empty
singleton (k:ks) v = Node Nothing $ Map.singleton k (singleton ks v)
union :: Ord a => Trie a b -> Trie a b -> Trie a b
union (Node u s) (Node v t) =
Node (mplus u v) (Map.unionWith union s t)
insert :: Ord a => [a] -> b -> Trie a b -> Trie a b
insert ks v t = union (singleton ks v) t
fromList :: Ord a => [([a], b)] -> Trie a b
fromList = foldr (uncurry insert) empty
size :: Trie a b -> Int
size = foldr (const succ) 0
joinTrie :: Ord a => Trie a (Trie a b) -> Trie a b
joinTrie (Node v t) = union (fromMaybe empty v) (Node Nothing $ joinTrie <$> t)
instance Ord a => Monad (Trie a) where
return x = singleton [] x
m >>= k = joinTrie (fmap k m)
instance Ord a => Applicative (Trie a) where
pure = return
(<*>) = ap
instance (Ord a, Arbitrary a, Arbitrary b) => Arbitrary (Map a b) where
arbitrary = Map.fromList <$> arbitrary
shrink = map Map.fromList . shrink . Map.toList
instance (Ord a, Arbitrary a, Arbitrary b) => Arbitrary (Trie a b) where
arbitrary = fromList <$> arbitrary
shrink (Node v t) =
[ empty | isJust v || not (Map.null t) ] ++
[ t | t <- Map.elems t ] ++
[ Node v t | v <- shrink v ] ++
[ Node v t | t <- shrink t ]
data Bit = O | I
deriving (Eq, Ord)
instance Show Bit where
show O = "0"
show I = "1"
showList bs = showString (concatMap show bs)
instance Arbitrary Bit where
arbitrary = elements [O, I]
shrink O = []
shrink I = [O]
type T' = Trie Bit
type T = T' Integer
infix 0 ===
x === y = whenFail (putStrLn $ show x ++ " /=\n" ++ show y) (x == y)
prop_monad1 :: T -> Property
prop_monad1 t = (t >>= return) === t
prop_monad2 :: Integer -> Fun Integer T -> Property
prop_monad2 x (Fun _ f) = (return x >>= f) === f x
prop_monad3 :: T -> Fun Integer T -> Fun Integer T -> Property
prop_monad3 m (Fun _ f) (Fun _ g) = (m >>= f >>= g) === (m >>= \x -> f x >>= g)
prop_app1 :: Fun Integer Integer -> T -> Property
prop_app1 (Fun _ f) t = pure f <*> t === fmap f t
prop_app2 :: T' (Fun Integer Integer) -> Integer -> Property
prop_app2 f x = fmap apply f <*> pure x === fmap (`apply` x) f
prop_app3 :: T' (Fun (Integer, Integer) Integer) -> T -> T -> Property
prop_app3 f x y = ((apply <$> f) <*> ((,) <$> x <*> y)) ===
((curry . apply <$> f) <*> x <*> y)