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 enqueueing 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_
Okasaki, Chapter 7.1—7.2. Although we will not cover this material in class, you are encouraged to read through this material to understand the basic ideas.