module Data.Functor.Representable.Trie.Bool ( BoolTrie (..) ) where
import Control.Applicative
import Data.Distributive
import Data.Functor.Representable
import Data.Functor.Bind
import Data.Foldable
import Data.Traversable
import Data.Semigroup
import Data.Semigroup.Foldable
import Data.Semigroup.Traversable
import Data.Key
import Prelude hiding (lookup)
data BoolTrie a = BoolTrie a a deriving (Eq,Ord,Show,Read)
false :: BoolTrie a -> a
false (BoolTrie a _) = a
true :: BoolTrie a -> a
true (BoolTrie _ b) = b
type instance Key BoolTrie = Bool
instance Functor BoolTrie where
  fmap f (BoolTrie a b) = BoolTrie (f a) (f b)
  b <$ _ = pure b
instance Apply BoolTrie where
  BoolTrie a b <.> BoolTrie c d = BoolTrie (a c) (b d)
  a <. _ = a
  _ .> b = b
instance Applicative BoolTrie where
  pure a = BoolTrie a a
  (<*>) = (<.>) 
  a <* _ = a
  _ *> b = b
instance Bind BoolTrie where
  BoolTrie a b >>- f = BoolTrie (false (f a)) (true (f b))
instance Monad BoolTrie where
  return = pure
  BoolTrie a b >>= f = BoolTrie (false (f a)) (true (f b))
  _ >> a = a
instance Keyed BoolTrie where
  mapWithKey f (BoolTrie a b) = BoolTrie (f False a) (f True b)
instance Zip BoolTrie where
  zipWith f (BoolTrie a b) (BoolTrie c d) = BoolTrie (f a c) (f b d)
instance ZipWithKey BoolTrie where
  zipWithKey f (BoolTrie a b) (BoolTrie c d) = BoolTrie (f False a c) (f True b d)
instance Foldable BoolTrie where
  foldMap f (BoolTrie a b) = f a `mappend` f b
instance Foldable1 BoolTrie where
  foldMap1 f (BoolTrie a b) = f a <> f b
instance Traversable BoolTrie where
  traverse f (BoolTrie a b) = BoolTrie <$> f a <*> f b
instance Traversable1 BoolTrie where
  traverse1 f (BoolTrie a b) = BoolTrie <$> f a <.> f b
instance FoldableWithKey BoolTrie where
  foldMapWithKey f (BoolTrie a b) = f False a `mappend` f True b
instance FoldableWithKey1 BoolTrie where
  foldMapWithKey1 f (BoolTrie a b) = f False a <> f True b
instance TraversableWithKey BoolTrie where
  traverseWithKey f (BoolTrie a b) = BoolTrie <$> f False a <*> f True b
instance TraversableWithKey1 BoolTrie where
  traverseWithKey1 f (BoolTrie a b) = BoolTrie <$> f False a <.> f True b
instance Distributive BoolTrie where
  distribute = distributeRep
instance Indexable BoolTrie where
  index (BoolTrie a _) False = a
  index (BoolTrie _ b) True  = b
instance Adjustable BoolTrie where
  adjust f False (BoolTrie a b) = BoolTrie (f a) b
  adjust f True (BoolTrie a b) = BoolTrie a (f b)
instance Lookup BoolTrie where
  lookup = lookupDefault
instance Representable BoolTrie where
  tabulate f = BoolTrie (f False) (f True)