{-# LANGUAGE LambdaCase, ScopedTypeVariables #-} module Data.Sequence.Circular where import qualified Data.Sequence as Containers -- $setup -- >>> import Data.List (nub) -- >>> import System.Mem.StableName (makeStableName) -- >>> s = Containers.fromList "abcd" type Seq a = Maybe (NonEmptySeq a) data NonEmptySeq a = NonEmptySeq { seqFirst :: SeqNode a , seqLast :: SeqNode a } data SeqNode a = SeqNode { seqNodePrev :: Maybe (SeqNode a) , seqNodeLabel :: a , seqNodeNext :: Maybe (SeqNode a) } -- | -- >>> Just (NonEmptySeq s1 s4') = freeze s -- >>> SeqNode Nothing 'a' (Just s2) = s1 -- >>> SeqNode (Just s1') 'b' (Just s3) = s2 -- >>> SeqNode (Just s2') 'c' (Just s4) = s3 -- >>> SeqNode (Just s3') 'd' Nothing = s4 -- >>> foldr seq () [s1, s1', s2, s2', s3, s3', s4, s4'] -- () -- >>> length . nub <$> mapM makeStableName [s1,s1'] -- 1 -- >>> length . nub <$> mapM makeStableName [s2,s2'] -- 1 -- >>> length . nub <$> mapM makeStableName [s3,s3'] -- 1 -- >>> length . nub <$> mapM makeStableName [s4,s4'] -- 1 freeze :: forall a. Containers.Seq a -> Seq a freeze = freezeSeq Nothing where freezeSeq :: Maybe (SeqNode a) -> Containers.Seq a -> Seq a freezeSeq prev = \case Containers.Empty -> Nothing a Containers.:<| as -> Just $ freezeNonEmptySeq prev a as freezeNonEmptySeq :: Maybe (SeqNode a) -> a -> Containers.Seq a -> NonEmptySeq a freezeNonEmptySeq prev a as = NonEmptySeq first last_ where first :: SeqNode a first = SeqNode prev a next seq_ :: Seq a seq_ = freezeSeq (Just first) as next :: Maybe (SeqNode a) next = fmap seqFirst seq_ last_ :: SeqNode a last_ = maybe first seqLast seq_ -- | -- >>> thaw (freeze s) == s -- True thaw :: forall a. Seq a -> Containers.Seq a thaw = go . fmap seqFirst where go :: Maybe (SeqNode a) -> Containers.Seq a go Nothing = Containers.Empty go (Just (SeqNode _ a next)) = a Containers.:<| go next