module Coda.Relative.Cat
( Cat
, snocCat
, singleton
, null
) where
import Control.Lens
import Data.Default
import Data.Function (on)
import Data.List (unfoldr)
import Data.Semigroup
import GHC.Exts as Exts
import Text.Read
import Prelude hiding (null)
import Coda.Relative.Class
import Coda.Relative.Queue hiding (null)
import qualified Coda.Relative.Queue as Q
data Cat a = E | C a (Queue (Cat a))
instance Default (Cat a) where
def = E
instance Relative a => Relative (Cat a) where
rel _ E = E
rel 0 xs = xs
rel d (C a as) = C (rel d a) (rel d as)
null :: Cat a -> Bool
null E = True
null _ = False
instance Relative a => Semigroup (Cat a) where
xs <> E = xs
E <> xs = xs
C x xs <> ys = link x xs ys
instance Relative a => Monoid (Cat a) where
mempty = E
mappend = (<>)
link :: Relative a => a -> Queue (Cat a) -> Cat a -> Cat a
link x q ys = C x (snocQ q ys)
linkAll :: Relative a => Queue (Cat a) -> Cat a
linkAll q = case uncons q of
Just (cat@(C a t), q')
| Q.null q' -> cat
| otherwise -> link a t (linkAll q')
Just (E, q') -> linkAll q'
Nothing -> E
instance AsEmpty (Cat a) where
_Empty = prism (const E) $ \case
E -> Right ()
xs -> Left xs
instance (Relative a, Relative b) => Cons (Cat a) (Cat b) a b where
_Cons = prism kons unkons where
kons (a, E) = C a def
kons (a, ys) = link a def ys
unkons E = Left E
unkons (C a q) = Right (a, linkAll q)
instance Relative a => IsList (Cat a) where
type Item (Cat a) = a
fromList = foldr cons E
toList = unfoldr uncons
singleton :: a -> Cat a
singleton a = C a def
snocCat :: Relative a => Cat a -> a -> Cat a
snocCat xs a = xs <> singleton a
instance (Show a, Relative a) => Show (Cat a) where
showsPrec d = showsPrec d . Exts.toList
instance (Read a, Relative a) => Read (Cat a) where
readPrec = Exts.fromList <$> readPrec
instance (Eq a, Relative a) => Eq (Cat a) where
(==) = (==) `on` Exts.toList
instance (Ord a, Relative a) => Ord (Cat a) where
compare = compare `on` Exts.toList