# Real-Time Queues

`RealTimeQueue.elm`

Combine `reverse` and `append` into an incremental function that performs one step of each at a time:

``````rotate : LazyList a -> List a -> LazyList a -> LazyList a
rotate xs ys acc =
case (force xs, ys) of
(Nil        , y::[])  -> lazy (\_ -> Cons y acc)
(Cons x xs_ , y::ys_) ->
lazy (\_ -> Cons x (rotate xs_ ys_ (lazy (\_ -> Cons y acc))))``````

Starting with the `BankersQueue`, use an ordinary `List` to describe the `back`, and track a “schedule” `LazyList a` that is a suffix of `front` that needs to be forced. The implementation enforces the invariant that the size of `sched` is equal to the size of `front` minus the size of `back`. This invariant obviates the need to maintain `Int` size information explicitly.

``type Queue a = Q (LazyList a) (List a) (LazyList a)``

The basic operations:

``````empty : Queue a
empty = Q (lazy (\_ -> Nil)) [] (lazy (\_ -> Nil))

isEmpty : Queue a -> Bool
isEmpty (Q front _ _) =
case force front of
Nil -> True
_   -> False

peek : Queue a -> Maybe a
peek (Q front _ _) = maybeHead front``````

Because of the invariant, `sched` is empty when the lengths of `front` and `back` are the same. So when `enqueue`ing an element, the rotation from `back` to `front` is initiated when `sched` is empty.

``````enqueue : a -> Queue a -> Queue a
enqueue x (Q front back sched) =
case force sched of
Cons _ sched_ -> Q front (x::back) sched_
Nil ->
let front_ = rotate front (x::back) (lazy (\_ -> Nil)) in
Q front_ [] front_``````

Similarly, `dequeue` initiates the rotation when the `back` becomes longer than the `front`.

``````dequeue : Queue a -> Maybe (Queue a)
dequeue (Q front back sched) =
case force front of
Nil -> Nothing
Cons _ front_ ->
case force sched of
Cons _ sched_ -> Just (Q front_ back sched_)
Nil ->
let front__ = rotate front_ back (lazy (\_ -> Nil)) in
Just (Q front__ [] front__)``````

The common parts of these operations can be factored out into an `exec` function.

``````enqueue : a -> Queue a -> Queue a
enqueue x (Q front back sched) = exec front (x::back) sched

dequeue : Queue a -> Maybe (Queue a)
dequeue (Q front back sched) =
case force front of
Nil       -> Nothing
Cons _ f_ -> Just (exec f_ back sched)

exec front back sched =
case force sched of
Cons _ sched_ -> Q front back sched_
Nil ->
let front_ = rotate front back (lazy (\_ -> Nil)) in
Q front_ [] front_``````