Queue
A queue is data structure that stores a sequence of elements, while supporting two basic operations: enqueue and dequeue
Let's visualize how it works:
 [0; 1; 2]
= { enqueue 42 }
 [0; 1; 2; 42]
 [0; 1; 2]
= { dequeue }
 0, [1; 2]
First restriction: rely on inmutable data structures
- Using a list we can rely on the operator ::for dequeueing, since pattern matchingx::xsO(1)
- However this means for enqueuing we need to do xs @ [x]which is O(n), wheren = xs.Length
Solution:
- rely on ::for bothenqueueanddequeue, since the operationx::xsis O(1)
- We can use two lists one enqueueing and one for dequeueing, frontandrearrespectively
- For dequeueing elements we do the pattern match x::xsonfrontgetting inxthe expected element, while inxsthe new value forfront.
- For enqueueing we repleace rearbyx::rear, however this list ends up reversed according the expected order when dequeueing, sincexis its first element and should be the last dequeued.
- At some point the dequeueoperation will leave empty thefrontlist. When that happens we can takerear, reverse it and use it as the newfrontwhile the newrearis an empty list.
type Queue<'a> = { front: 'a list; rear: 'a list }
let enqueue (q: Queue<'a>) (x: 'a) = { q with rear = x :: q.rear }
let dequeue (q: Queue<'a>) =
  match q.front, List.rev q.rear with
  | [], [] -> None
  | [], x :: xs -> Some(x, { front = xs; rear = [] })
  | x :: xs, _ -> Some(x, { q with front = xs })
let rec queueToSeq (q: Queue<'a>) =
  seq {
    match dequeue q with
    | None -> ()
    | Some(x, nq) ->
      yield x
      yield! queueToSeq nq
  }
Let's make a simple test for our algorithm:
let xs = Seq.init 10 id |> Seq.toList
let q = xs |> Seq.fold (fun q x -> enqueue q x) {front = []; rear = []}
let ys = queueToSeq q |> Seq.toList
List.zip xs ys |> List.forall (fun (x, y) -> x = y)
True
Notice that in the current implementation of Microsoft's F# compiler, the following pattern match
match q.front, List.rev q.rear with
| [], [] -> ...
| [], x :: xs -> ...
| x :: xs, _ -> ...
evaluates List.rev q.rear always before matching any branch. This means that the code could easily be made more efficient. However, I think it makes no sense to evaluate such an expression until after q.front has been matched, since in some situations this would be sufficient to decide which branch to take. For this reason, I prefer to present the algorithm as it is, and leave it to the reader to optimise it if they think it is necessary.
type Queue<'a> =
  {
    front: 'a list
    rear: 'a list
  }
'a
type 'T list = List<'T>
val enqueue: q: Queue<'a> -> x: 'a -> Queue<'a>
val q: Queue<'a>
val x: 'a
Queue.rear: 'a list
val dequeue: q: Queue<'a> -> ('a * Queue<'a>) option
Queue.front: 'a list
Multiple items
module List from Microsoft.FSharp.Collections
--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T member IsEmpty: bool member Item: index: int -> 'T with get ...
module List from Microsoft.FSharp.Collections
--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T member IsEmpty: bool member Item: index: int -> 'T with get ...
val rev: list: 'T list -> 'T list
union case Option.None: Option<'T>
val xs: 'a list
union case Option.Some: Value: 'T -> Option<'T>
val queueToSeq: q: Queue<'a> -> 'a seq
Multiple items
val seq: sequence: 'T seq -> 'T seq
--------------------
type 'T seq = System.Collections.Generic.IEnumerable<'T>
val seq: sequence: 'T seq -> 'T seq
--------------------
type 'T seq = System.Collections.Generic.IEnumerable<'T>
val nq: Queue<'a>
val xs: int list
module Seq
from Microsoft.FSharp.Collections
val init: count: int -> initializer: (int -> 'T) -> 'T seq
val id: x: 'T -> 'T
val toList: source: 'T seq -> 'T list
val q: Queue<int>
val fold<'T,'State> : folder: ('State -> 'T -> 'State) -> state: 'State -> source: 'T seq -> 'State
val x: int
val ys: int list
val zip: list1: 'T1 list -> list2: 'T2 list -> ('T1 * 'T2) list
val forall: predicate: ('T -> bool) -> list: 'T list -> bool
val y: int
     structured_programming_in_fsharp
            structured_programming_in_fsharp