packages feed

control-monad-queue-0.0.9: Data/Queue/TwoStack.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Queue.TwoStack
-- Copyright   :  (c) Leon P Smith 2009
-- License     :  BSD3
--
-- Maintainer  :  leon at melding-monads dot com
-- Stability   :  experimental
-- Portability :  portable
--
-- Two-Stack Queues of functional programming folklore.
-- Notably mentioned inside Chris Okasaki's thesis, with
-- relevant citations.
--
-- /Purely Functional Data Structures/ by Chris Okasaki,
-- /Cambridge University Press/,  1998
--
-- http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf
--
-----------------------------------------------------------------------------

module Data.Queue.TwoStack
     ( Q()
     , empty
     , enque
     , deque
     , listToQueue
     , queueToList
     , len
     ) where

import qualified Data.Queue.Class as Class
import Data.List

import Control.Monad.Queue.Util

data Q e = Q !LenType [e] [e]

instance Functor Q where
  fmap f (Q n as zs) = Q n (map f as ++ map f (reverse zs)) []

instance (Eq e) => Eq (Q e) where
  (Q ln as ys) == (Q mn bs zs)   =  ln == mn  &&  loop   as bs ys zs
    where
      loop as bs (y:ys) (z:zs)   =  y == z    &&  loop   as bs ys zs
      loop as bs ys     zs       =                loop2  as bs ys zs

      loop2 (a:as) (b:bs) ys zs  =  a == b    &&  loop2  as bs ys zs
      loop2 as     []     [] zs  =  as == reverse zs
      loop2 []     bs     ys []  =  bs == reverse ys

instance (Ord e) => Ord (Q e) where
  compare (Q _ as ys) (Q _ bs zs) = loop as bs ys zs
     where
       loop (a:as) (b:bs) ys zs
          = case compare a b of
             LT -> LT
             EQ -> loop as bs ys zs
             GT -> GT
       loop [] [] [] [] = EQ
       loop [] bs [] zs = LT
       loop [] bs ys zs = loop (reverse ys) bs [] zs
       loop as [] ys [] = GT
       loop as [] ys zs = loop as (reverse zs) ys []

empty :: Q e
empty =  Q 0 [] []

enque :: e -> Q e -> Q e
enque z  (Q 0 []     [])  = Q 1     [z]     []
enque z  (Q n (a:as) zs)  = Q (n+1) (a:as)  (z:zs)

deque :: Q e -> (Maybe e, Q e)
deque    (Q 0 []     [])  =   ( Nothing  ,  Q 0     []   []  )
deque    (Q n (a:as) zs)
         |  null as       =   ( Just a   ,  Q (n-1) as'  []  )
         |  otherwise     =   ( Just a   ,  Q (n-1) as   zs  )
            where as'     = reverse zs

listToQueue :: [e] -> Q e
listToQueue as = Q (genericLength as) as []

queueToList :: Q e -> [e]
queueToList (Q _ as zs) = as ++ reverse zs

len :: Q e -> LenType
len (Q l _ _) = l


instance Class.Queue Q where
  empty = empty
  enque = enque
  deque = deque