# Deque — foundational two-list double-ended queue for Bend.
# Publish entry for this package. Depends only on Base.
#
# Encoding: front + rear (rear stored reversed). Each side is normalized only
# when that side is empty, so transfers are amortized over the operations.
import Base
type Deque is Kind(a):
D{front: List, rear: List}
type Deque.Pop is Kind(a):
P{value: A, rest: Deque}
def Deque.empty(a, -A: Kind(a)) -> Deque:
D{Nil{}, Nil{}}
def Deque.push_front(a, -A: Kind(a), q: Deque, x: A) -> Deque:
match q:
case D{f, r}:
D{x <> f, r}
def Deque.push_back(a, -A: Kind(a), q: Deque, x: A) -> Deque:
match q:
case D{f, r}:
D{f, x <> r}
# When front is empty, reverse rear into front.
def Deque.norm_front(a, -A: Kind(a), q: Deque) -> Deque:
match q:
case D{f, r}:
match f:
case Nil{}:
D{List.reverse(a, A, r), Nil{}}
case h <> t:
D{h <> t, r}
# When rear is empty, reverse front into rear.
def Deque.norm_back(a, -A: Kind(a), q: Deque) -> Deque:
match q:
case D{f, r}:
match r:
case Nil{}:
D{Nil{}, List.reverse(a, A, f)}
case h <> t:
D{f, h <> t}
def Deque.pop_front.go(a, -A: Kind(a), q: Deque) -> Maybe>:
match q:
case D{f, r}:
match f:
case Nil{}:
None{}
case h <> t:
Some{P{h, D{t, r}}}
def Deque.pop_front(a, -A: Kind(a), q: Deque) -> Maybe>:
Deque.pop_front.go(a, A, Deque.norm_front(a, A, q))
def Deque.pop_back.go(a, -A: Kind(a), q: Deque) -> Maybe>:
match q:
case D{f, r}:
match r:
case Nil{}:
None{}
case h <> t:
Some{P{h, D{f, t}}}
def Deque.pop_back(a, -A: Kind(a), q: Deque) -> Maybe>:
Deque.pop_back.go(a, A, Deque.norm_back(a, A, q))
def Deque.peek_front.go(a, -A: Kind(a), q: Deque) -> Maybe:
match q:
case D{f, r}:
match f:
case Nil{}:
None{}
case h <> t:
Some{h}
def Deque.peek_front(a, -A: Kind(a), q: Deque) -> Maybe:
Deque.peek_front.go(a, A, Deque.norm_front(a, A, q))
def Deque.peek_back.go(a, -A: Kind(a), q: Deque) -> Maybe:
match q:
case D{f, r}:
match r:
case Nil{}:
None{}
case h <> t:
Some{h}
def Deque.peek_back(a, -A: Kind(a), q: Deque) -> Maybe:
Deque.peek_back.go(a, A, Deque.norm_back(a, A, q))
def Deque.is_empty(a, -A: Kind(a), q: Deque) -> Bool:
match q:
case D{f, r}:
match f r:
case Nil{} Nil{}:
True{}
case _ _:
False{}
def Deque.length(a, -A: Kind(a), q: Deque) -> Nat:
match q:
case D{f, r}:
Nat.add(List.length(a, A, f), List.length(a, A, r))
# Logical order is front ++ reverse(rear).
def Deque.to_list(a, -A: Kind(a), q: Deque) -> List:
match q:
case D{f, r}:
List.append(a, A, f, List.reverse(a, A, r))
def Deque.from_list(a, -A: Kind(a), xs: List) -> Deque:
D{xs, Nil{}}