An immutable queue library in F#. The queue is divided into two lists : one for dequeueing, and one for enqueueing. All operations are based on the List module.
There are a few exceptions however : operations involving arithmetic (such as List.sum) are not included.
Source
// Adapted from F# ListEnumerator from fslib/prim-types.fs
type private QueueEnumerator<'a>(enqueued : 'a list, toDequeue :'a list) =
static let notStarted() =
raise (new System.InvalidOperationException("Enumeration has not started. Call MoveNext."))
static let alreadyFinished() =
raise (new System.InvalidOperationException("Enumeration already finished."))
static let nonempty x = not <| List.isEmpty x
let mutable backData = enqueued
let mutable frontData = toDequeue
let moveBackToFront() =
match frontData, backData with
| [], hd::tl -> frontData <- List.rev backData
| _ -> ()
let mutable started = false
member x.GetCurrent() =
if started then
moveBackToFront()
match frontData with
| hd :: tl -> hd
| [] -> alreadyFinished()
else
notStarted()
interface System.Collections.Generic.IEnumerator<'a> with
member x.Current = x.GetCurrent()
interface System.Collections.IEnumerator with
member x.MoveNext() =
moveBackToFront()
if started then
match frontData with
| hd::tl ->
frontData <- tl
nonempty frontData
| [] -> false
else
started <- true
nonempty frontData
member x.Current = box (x.GetCurrent())
member x.Reset() =
started <- false
backData <- enqueued
frontData <- toDequeue
interface System.IDisposable with
member x.Dispose() = ()
type Queue<'a> =
{ enqueued : 'a list
toDequeue : 'a list
}
interface System.Collections.Generic.IEnumerable<'a> with
member x.GetEnumerator() =
(new QueueEnumerator<'a>(x.enqueued, x.toDequeue) :> System.Collections.Generic.IEnumerator<'a>)
interface System.Collections.IEnumerable with
member x.GetEnumerator() =
(new QueueEnumerator<'a>(x.enqueued, x.toDequeue) :> System.Collections.IEnumerator)
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Queue =
type t<'a> = Queue<'a>
let unsafe_create enqueued toDequeue =
{ enqueued = enqueued
toDequeue = toDequeue
}
let toList xs = xs.toDequeue @ List.rev xs.enqueued
let ofList xs = unsafe_create [] xs
[<GeneralizableValueAttribute ()>]
let empty<'a> : Queue<'a> = unsafe_create [] []
let rec peek q =
match q.enqueued, q.toDequeue with
| _, hd::tl -> hd
| hd::tl as e, [] -> e |> List.rev |> List.head
| _ -> invalidArg "q" "peek : empty queue"
let rec tryPeek q =
match q.enqueued, q.toDequeue with
| _, hd::tl -> Some hd
| hd::tl as e, [] -> e |> List.rev |> ofList |> tryPeek
| _ -> None
let enqueue x q = {q with enqueued = x :: q.enqueued}
let rec dequeue q =
match q.enqueued, q.toDequeue with
| _, hd::tl -> hd, {q with toDequeue = tl}
| hd::tl as e, [] -> e |> List.rev |> ofList |> dequeue
| _ -> invalidArg "q" "dequeue : empty queue"
let rec tryDequeue q =
match q.enqueued, q.toDequeue with
| _, hd::tl -> Some (hd, {q with toDequeue = tl})
| hd::tl as e, [] -> e |> List.rev |> ofList |> tryDequeue
| _ -> None
let append xs xs' = List.append (toList xs) (toList xs') |> ofList
let choose f xs =
unsafe_create (List.choose f xs.enqueued) (List.choose f xs.toDequeue)
let collect f xs =
unsafe_create (List.collect f xs.enqueued) (List.collect f xs.toDequeue)
let concat xss = unsafe_create [] [for xs in xss do yield! toList xs]
let exists p xs =
List.exists p xs.enqueued || List.exists p xs.toDequeue
let exists2 p xs xs' = List.exists2 p (toList xs) (toList xs')
let filter p xs =
unsafe_create (List.filter p xs.enqueued) (List.filter p xs.toDequeue)
let find p xs =
match List.tryFind p xs.toDequeue with
| None -> List.find p (List.rev xs.enqueued)
| Some x -> x
let findAll p xs = filter p xs
let findIndex p xs =
match List.tryFindIndex p xs.toDequeue with
| None -> List.findIndex p (List.rev xs.enqueued)
| Some x -> x
let fold f v xs = xs |> toList |> List.fold f v
let fold2 f v xs xs' = List.fold2 f v (toList xs) (toList xs')
let foldBack f xs v = List.foldBack f (toList xs) v
let foldBack2 f xs xs' v = List.foldBack2 f (toList xs) (toList xs') v
let forAll p xs =
List.forall p xs.enqueued && List.forall p xs.toDequeue
let forAll2 p xs xs' =
List.forall2 p (toList xs) (toList xs')
let head xs = peek xs
let init n f = List.init n f |> ofList
let isEmpty q = List.isEmpty q.enqueued && List.isEmpty q.toDequeue
let iter f xs =
List.iter f xs.toDequeue
xs.enqueued |> List.rev |> List.iter f
let iter2 f xs xs' = List.iter2 f (toList xs) (toList xs')
let iteri f xs =
List.iteri f xs.toDequeue
xs.enqueued |> List.rev |> List.iteri f
let iteri2 f xs xs' = List.iteri2 f (toList xs) (toList xs')
let length xs =
List.length xs.enqueued + List.length xs.toDequeue
let map f xs =
unsafe_create (List.map f xs.enqueued) (List.map f xs.toDequeue)
let map2 f xs xs' =
List.map2 f (toList xs) (toList xs') |> ofList
let map3 f xs xs' xs'' =
List.map3 f (toList xs) (toList xs') (toList xs'') |> ofList
let mapi f xs =
unsafe_create (List.mapi f xs.enqueued) (List.mapi f xs.toDequeue)
let mapi2 f xs xs' =
List.mapi2 f (toList xs) (toList xs') |> ofList
let nonempty xs = not <| isEmpty xs
let nth xs pos =
if pos > xs.toDequeue.Length then
List.nth (List.rev xs.enqueued) (pos - xs.toDequeue.Length)
else
List.nth xs.toDequeue pos
let fromArray xs = xs |> List.ofArray |> ofList
let toArray xs = xs |> toList |> List.toArray
let fromSeq xs = xs |> List.ofSeq |> ofList
let toSeq xs = xs |> toList |> List.toSeq
let min xs = List.min (toList xs)
let minBy f xs = List.minBy f (toList xs)
let max xs = List.max (toList xs)
let maxBy f xs = List.maxBy f (toList xs)
let partition p xs =
let enqueuedA, enqueuedB = List.partition p xs.enqueued
let toDequeueA, toDequeueB = List.partition p xs.toDequeue
unsafe_create enqueuedA toDequeueA, unsafe_create enqueuedB toDequeueB
let permute f xs =
xs |> toList |> List.permute f |> ofList
let pick p xs =
match List.tryPick p xs.toDequeue with
| None -> List.pick p (List.rev xs.enqueued)
| Some res -> res
let reduce f xs = xs |> toList |> List.reduce f
let reduceBack f xs = xs |> toList |> List.reduceBack f
let replicate n x = List.replicate n x |> ofList
let rev xs =
unsafe_create (List.rev xs.toDequeue) (List.rev xs.enqueued)
let scan f v xs = xs |> toList |> List.scan f v |> ofList
let scanBack f xs v = List.scanBack f (toList xs) v |> ofList
let sort xs = List.sort (toList xs) |> ofList
let sortBy f xs = List.sortBy f (toList xs) |> ofList
let sortWith f xs = List.sortWith f (toList xs) |> ofList
let tail xs =
let hd, tl = dequeue xs
tl
let tryFind p xs =
match List.tryFind p xs.toDequeue with
| None -> List.tryFind p (List.rev xs.enqueued)
| Some _ as res -> res
let tryFindIndex p xs =
match List.tryFindIndex p xs.toDequeue with
| None -> List.tryFindIndex p (List.rev xs.enqueued)
| Some _ as res -> res
let tryPick p xs =
match List.tryPick p xs.toDequeue with
| None -> List.tryPick p (List.rev xs.enqueued)
| Some _ as res -> res
Signature
type Queue<'a> =
{ enqueued : 'a list
toDequeue : 'a list
}
interface System.Collections.IEnumerable
interface System.Collections.Generic.IEnumerable<'a>
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Queue =
type t<'a> = Queue<'a>
val toList : t<'a> -> 'a list
val ofList : 'a list -> t<'a>
val empty<'a> : t<'a>
val peek : t<'a> -> 'a
val tryPeek : t<'a> -> 'a option
val enqueue : 'a -> t<'a> -> t<'a>
val dequeue : t<'a> -> 'a * t<'a>
val tryDequeue : t<'a> -> ('a * t<'a>) option
val append : t<'a> -> t<'a> -> t<'a>
val choose : ('a -> 'b option) -> t<'a> -> t<'b>
val collect : ('a -> 'b list) -> t<'a> -> t<'b>
val concat : seq<t<'a>> -> t<'a>
val exists : ('a -> bool) -> t<'a> -> bool
val exists2 : ('a -> 'b -> bool) -> t<'a> -> t<'b> -> bool
val filter : ('a -> bool) -> t<'a> -> t<'a>
val find : ('a -> bool) -> t<'a> -> 'a
val findAll : ('a -> bool) -> t<'a> -> t<'a>
val findIndex : ('a -> bool) -> t<'a> -> int
val fold : ('a -> 'b -> 'a) -> 'a -> t<'b> -> 'a
val fold2 : ('a -> 'b -> 'c -> 'a) -> 'a -> t<'b> -> t<'c> -> 'a
val foldBack : ('a -> 'b -> 'b) -> t<'a> -> 'b -> 'b
val foldBack2 : ('a -> 'b -> 'c -> 'c) -> t<'a> -> t<'b> -> 'c -> 'c
val forAll : ('a -> bool) -> t<'a> -> bool
val forAll2 : ('a -> 'b -> bool) -> t<'a> -> t<'b> -> bool
val head : t<'a> -> 'a
val init : int -> (int -> 'a) -> t<'a>
val isEmpty : t<'a> -> bool
val iter : ('a -> unit) -> t<'a> -> unit
val iter2 : ('a -> 'b -> unit) -> t<'a> -> t<'b> -> unit
val iteri : (int -> 'a -> unit) -> t<'a> -> unit
val iteri2 : (int -> 'a -> 'b -> unit) -> t<'a> -> t<'b> -> unit
val length : t<'a> -> int
val map : ('a -> 'b) -> t<'a> -> t<'b>
val map2 : ('a -> 'b -> 'c) -> t<'a> -> t<'b> -> t<'c>
val map3 : ('a -> 'b -> 'c -> 'd) -> t<'a> -> t<'b> -> t<'c> -> t<'d>
val mapi : (int -> 'a -> 'b) -> t<'a> -> t<'b>
val mapi2 : (int -> 'a -> 'b -> 'c) -> t<'a> -> t<'b> -> t<'c>
val min : t<'a> -> 'a when 'a:comparison
val minBy : ('a -> 'b) -> t<'a> -> 'a when 'b:comparison
val max : t<'a> -> 'a when 'a:comparison
val maxBy : ('a -> 'b) -> t<'a> -> 'a when 'b:comparison
val nonempty : t<'a> -> bool
val nth : t<'a> -> int -> 'a
val fromArray : 'a array -> t<'a>
val toArray : t<'a> -> 'a array
val fromSeq : seq<'b> -> t<'b>
val toSeq : t<'a> -> seq<'a>
val partition : ('a -> bool) -> t<'a> -> t<'a> * t<'a>
val permute : (int -> int) -> t<'a> -> t<'a>
val pick : ('a -> option<'b>) -> t<'a> -> 'b
val reduce : ('a -> 'a -> 'a) -> t<'a> -> 'a
val reduceBack : ('a -> 'a -> 'a) -> t<'a> -> 'a
val replicate : int -> 'a -> t<'a>
val rev : t<'a> -> t<'a>
val scan : ('a -> 'b -> 'a) -> 'a -> t<'b> -> t<'a>
val scanBack : ('a -> 'b -> 'b) -> t<'a> -> 'b -> t<'b>
val sort : t<'a> -> t<'a> when 'a: comparison
val sortBy : ('a -> 'b) -> t<'a> -> t<'a> when 'b: comparison
val sortWith : ('a -> 'a -> int) -> t<'a> -> t<'a>
val tail : t<'a> -> t<'a>
val tryFind : ('a -> bool) -> t<'a> -> option<'a>
val tryFindIndex : ('a -> bool) -> t<'a> -> option<int>
val tryPick : ('a -> 'b option) -> t<'a> -> option<'b>

Very cool. You should submit this to the F# Power Pack.