packages feed

sequence-0.9.9.0: Data/Sequence/ToCatQueue/Internal.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE BangPatterns #-}
#if __GLASGOW_HASKELL__ < 710
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
#endif


-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Sequence.ToCatQueue.Internal
-- Copyright   :  (c) Atze van der Ploeg 2013
-- License     :  BSD-style
-- Maintainer  :  atzeus@gmail.org
-- Stability   :  provisional
-- Portability :  portable
--
-- A purely functional catenable queue representation with
-- that turns takes a purely functional queue and turns in it into
-- a catenable queue, i.e. with the same complexity for '><' as for '|>'
-- Based on Purely functional data structures by Chris Okasaki 
-- section 7.2: Catenable lists
--
-----------------------------------------------------------------------------

module Data.Sequence.ToCatQueue.Internal
  ( ToCatQueue (..)
  ) where
import Control.Applicative hiding (empty)
import Data.Foldable
import Data.Traversable
import Data.Monoid (Monoid (..))
import qualified Text.Read as TR
#if MIN_VERSION_base(4,9,0)
import qualified Data.Semigroup as Semigroup
import Data.Functor.Classes (Show1 (..))
#endif
import Data.Function (on)
import Prelude hiding (foldr,foldl)
import Data.SequenceClass

-- | The catenable queue type. The first type argument is the 
-- type of the queue we use (|>)
data ToCatQueue q a where
  -- Invariant: no element of the queue of queues may
  -- be empty.
  C0 :: ToCatQueue q a
  CN :: a -> !(q (ToCatQueue q a)) -> ToCatQueue q a

deriving instance Functor q => Functor (ToCatQueue q)
deriving instance Foldable q => Foldable (ToCatQueue q)
deriving instance Traversable q => Traversable (ToCatQueue q)

instance (Show a, Foldable q) => Show (ToCatQueue q a) where
    showsPrec p xs = showParen (p > 10) $
        showString "fromList " . shows (toList xs)

#if MIN_VERSION_base(4,9,0)
instance Foldable q => Show1 (ToCatQueue q) where
  liftShowsPrec _shwsPrc shwList p xs = showParen (p > 10) $
        showString "fromList " . shwList (toList xs)
#endif

instance (Sequence q, Read a) => Read (ToCatQueue q a) where
    readPrec = TR.parens $ TR.prec 10 $ do
        TR.Ident "fromList" <- TR.lexP
        xs <- TR.readPrec
        return (fromList xs)

    readListPrec = TR.readListPrecDefault

instance (Foldable q, Eq a) => Eq (ToCatQueue q a) where
  (==) = (==) `on` toList

instance (Foldable q, Ord a) => Ord (ToCatQueue q a) where
  compare = compare `on` toList

instance Sequence q => Sequence (ToCatQueue q) where
 empty       = C0
 singleton a = CN a empty
 C0        >< ys  = ys
 xs        >< C0  = xs
 (CN x q)  >< ys  = CN x (q |> ys)

 viewl C0        = EmptyL
 viewl (CN x0 q0)  = x0 :< case viewl q0 of
   EmptyL -> C0
   t :< q'  -> linkAll t q'
   where
   linkAll :: ToCatQueue q a -> q (ToCatQueue q a) -> ToCatQueue q a
   linkAll t@(CN x q) q' = case viewl q' of
     EmptyL -> t
     h :< t' -> CN x (q |> linkAll h t')
   linkAll C0 _ = error "Invariant failure"

 viewr = foldl' go EmptyR
   where
     go EmptyR y = empty :> y
     go (xs :> x) y = xs' :> y
       where
         !xs' = xs |> x

#if MIN_VERSION_base(4,9,0)
instance Sequence q => Semigroup.Semigroup (ToCatQueue q a) where
  (<>) = (><)
#endif
instance Sequence q => Monoid (ToCatQueue q a) where
  mempty = empty
#if MIN_VERSION_base(4,9,0)
  mappend = (Semigroup.<>)
#else
  mappend = (><)
#endif