summaryrefslogtreecommitdiff
path: root/Haskell-book/28/DifferenceList/src/Data/Queue.hs
blob: 68d1e1fcaf96431140e5b713c36ac9e9933d9a38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
module Data.Queue
    ( Queue(..)
    , empty
    , isEmpty
    , push
    , pop
    ) where

-- From Okasaki's Purely Functional Data Structures
data Queue a =
    Queue { enqueue :: [a]
          , dequeue :: [a]
          } deriving (Eq, Show)

isEmpty :: Queue a -> Bool
isEmpty xs = length (enqueue xs) == 0
          && length (dequeue xs) == 0

empty :: Queue a
empty = Queue [] []

-- adds an item
push :: a -> Queue a -> Queue a
push x xs = Queue { enqueue = x : (enqueue xs)
                  , dequeue = dequeue xs }

pop :: Queue a -> Maybe (a, Queue a)
pop xs = popFromLists (enqueue xs) (dequeue xs)
    where popFromLists [] [] = Nothing
          popFromLists en (d:de) = Just (d, Queue en de)
          popFromLists en [] = popFromLists [] (reverse en)

-- We’re going to give you less code this time, but your task is to
-- implement the above and write a benchmark comparing it against
-- performing alternating pushes and pops from a queue based on a
-- single list. Alternating so that you can’t take advantage of reversing
-- the list after a long series of pushes in order to perform a long series
-- of pops efficiently.
--
-- Don’t forget to handle the case where the dequeue is empty and
-- you need to shift items from the enqueue to the dequeue. You need
-- to do so without violating “first come, first served”.
-- Lastly, benchmark it against Sequence. Come up with a variety of
-- tests. Add additional operations for your Queue type if you want.