diff --git a/Control/Monad/Queue.hs b/Control/Monad/Queue.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Queue.hs
@@ -0,0 +1,4 @@
+module Control.Monad.Queue (module Control.Monad.Queue.Instances, module Control.Monad.Queue.Class) where
+
+import Control.Monad.Queue.Instances
+import Control.Monad.Queue.Class
diff --git a/Control/Monad/Queue/Class.hs b/Control/Monad/Queue/Class.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Queue/Class.hs
@@ -0,0 +1,140 @@
+{-# LANGUAGE TypeOperators, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}
+
+module Control.Monad.Queue.Class ((:->)(..), MonadQueue(..)) where
+
+import qualified Control.Monad.State.Strict as StrictS
+import qualified Control.Monad.State.Lazy as LazyS
+import Control.Monad.List
+import Control.Monad.Reader
+import Control.Monad.Maybe
+import Control.Monad.Array
+import Control.Monad.ST.Trans
+import Control.Monad.Trans.Operations
+import qualified Control.Monad.Writer.Strict as StrictW
+import qualified Control.Monad.Writer.Lazy as LazyW
+import Data.Monoid(Monoid)
+
+-- | Type that only orders on the key, ignoring the value completely; frequently useful in priority queues, so made available here.
+data e :-> f = e :-> f
+
+instance Eq f => Eq (e :-> f) where
+	(_ :-> x) == (_ :-> y) = x == y
+instance Ord f => Ord (e :-> f) where
+	(_ :-> x) `compare` (_ :-> y)	= compare x y
+
+-- | Typeclass abstraction of a monad with access to a mutable queue.  Minimal implementation: 'queueInsert' or 'queueInsertAll', 'queuePeek', 'queueExtract' or 'queueDelete', 'queueSize'.
+class Monad m => MonadQueue e m | m -> e where
+	queueInsert :: e -> m ()
+	queueInsertAll :: [e] -> m ()
+	queueExtract :: m (Maybe e)
+	queueDelete :: m ()
+	queuePeek :: m (Maybe e)
+	queueEmpty :: m Bool
+	queueSize :: m Int
+	queueEmpty = liftM (==0) queueSize
+	queueInsertAll = mapM_ queueInsert
+	queueInsert x = queueInsertAll [x]
+	queueDelete = queueExtract >> return ()
+	queueExtract = do	mx <- queuePeek
+				case mx of	Nothing	-> return Nothing
+						Just{}	-> queueDelete >> return mx
+
+-- instance (MonadTrans t, MonadQueue e m, Monad (t m)) => MonadQueue e (t m) where
+-- 	queueInsert = lift . queueInsert
+-- 	queueInsertAll = lift . queueInsertAll
+-- 	queueExtract = lift queueExtract
+-- 	queueDelete = lift queueDelete
+-- 	queuePeek = lift queuePeek
+-- 	queueEmpty = lift queueEmpty
+-- 	queueSize = lift queueSize
+	
+	
+instance MonadQueue e m => MonadQueue e (StrictS.StateT s m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+	
+instance MonadQueue e m => MonadQueue e (LazyS.StateT s m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+	
+instance MonadQueue e m => MonadQueue e (ReaderT r m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+	
+instance (Monoid w, MonadQueue e m) => MonadQueue e (StrictW.WriterT w m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+	
+instance (Monoid w, MonadQueue e m) => MonadQueue e (LazyW.WriterT w m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+	
+instance MonadQueue e m => MonadQueue e (MaybeT m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+	
+instance MonadQueue e m => MonadQueue e (ListT m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+	
+instance MonadQueue e m => MonadQueue e (ArrayT f m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+	
+instance MonadQueue e m => MonadQueue e (IntMapT f m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
+
+instance MonadQueue e m => MonadQueue e (STT s m) where
+	queueInsert = lift . queueInsert
+	queueInsertAll = lift . queueInsertAll
+	queueExtract = lift queueExtract
+	queueDelete = lift queueDelete
+	queuePeek = lift queuePeek
+	queueEmpty = lift queueEmpty
+	queueSize = lift queueSize
diff --git a/Control/Monad/Queue/Heap.hs b/Control/Monad/Queue/Heap.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Queue/Heap.hs
@@ -0,0 +1,79 @@
+{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, UndecidableInstances #-}
+
+module Control.Monad.Queue.Heap (HeapT, HeapM, runHeapT, runHeapM) where
+
+import Control.Monad.State.Strict
+import Control.Monad.Array
+import Control.Monad.ST.Class
+import Control.Monad
+import Control.Monad.RWS.Class
+import Control.Monad.Queue.Class
+import Control.Monad.Identity
+
+-- | Monad transformer based on an array implementation of a standard binary heap.
+newtype HeapT e m a = HeapT {runHeapT :: ArrayT e (StateT Int m) a} deriving (Monad, MonadReader r, MonadST s, MonadWriter w, MonadFix, MonadIO)
+type HeapM e = HeapT e Identity
+
+-- | Runs an 'HeapT' transformer starting with an empty heap.
+runHeapT :: (Monad m, Ord e) => HeapT e m a -> m a
+runHeapT m = evalStateT (runArrayT_ 16 (runHeapT m)) 0
+
+-- | Runs an 'HeapT' transformer starting with a heap initialized to hold the specified list.  (Since this can be done with linear preprocessing, this is more efficient than inserting the elements one by one.)
+runHeapTOn :: (Monad m, Ord e) => HeapT e m a -- ^ The transformer operation.
+					-> Int -- ^ The starting size of the heap (must be equal to the length of the list)
+					-> [e] -- ^ The initial contents of the heap
+					-> m a
+runHeapTOn m n l = flip evalStateT n $ runArrayT_ 16 $ do	mapM_ (uncurry unsafeWriteAt) (zip [0..] l)
+								mapM_ (\ i -> unsafeReadAt i >>= heapDown n i) [0..n-1]
+								runHeapT m
+
+runHeapM :: Ord e => HeapM e a -> a
+runHeapM = runIdentity . runHeapT
+
+runHeapMOn :: Ord e => HeapM e a -> Int -> [e] -> a
+runHeapMOn m n l = runIdentity (runHeapTOn m n l)
+
+instance MonadTrans (HeapT e) where
+	lift = HeapT . lift . lift
+
+ensureHeap :: MonadArray e m => Int -> m ()
+ensureHeap n = do	cap <- getSize
+			when (n - 1 >= cap) (resize (2 * n))
+
+heapUp :: (MonadArray e m, Ord e) => Int -> e -> m ()
+heapUp = let	heapUp' 0 x	= unsafeWriteAt 0 x
+		heapUp' i x	= let j = (i - 1) `quot` 2 in do
+			aj <- unsafeReadAt j
+			if x >= aj then unsafeWriteAt i x else unsafeWriteAt i aj >> heapUp' j x
+		in heapUp'
+
+heapDown :: (MonadArray e m, Ord e) => Int -> Int -> e -> m ()
+heapDown size = heapDown'
+	where	heapDown' i x = let lch = 2 * i + 1; rch = lch + 1 in case compare rch size of
+			LT	-> do	al <- unsafeReadAt lch
+					ar <- unsafeReadAt rch
+					let (ach, ch) = if al < ar then (al, lch) else (ar, rch)
+					if ach < x then unsafeWriteAt i ach >> heapDown' ch x else unsafeWriteAt i x
+			EQ	-> do	al <- readAt lch
+					if al < x then unsafeWriteAt i al >> unsafeWriteAt lch x else unsafeWriteAt i x
+			GT	-> unsafeWriteAt i x
+
+instance (Ord e, Monad m) => MonadQueue e (HeapT e m) where
+	{-# SPECIALIZE instance Ord e => MonadQueue e (HeapT e Identity) #-}
+	queuePeek = HeapT $ do	
+		size <- get
+		if size > 0 then liftM Just (unsafeReadAt 0) else return Nothing
+	queueInsert x = HeapT $ do
+		size <- get
+		ensureHeap (size+1)
+		put (size + 1)
+		heapUp size x
+	queueDelete = HeapT $ do
+		size <- get
+		put (size - 1)
+		unsafeReadAt (size - 1) >>= heapDown (size - 1) 0 >> unsafeWriteAt (size-1) undefined
+	queueSize = HeapT get
+
+instance MonadState s m => MonadState s (HeapT e m) where
+	get = lift get
+	put = lift . put
diff --git a/Control/Monad/Queue/Instances.hs b/Control/Monad/Queue/Instances.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Queue/Instances.hs
@@ -0,0 +1,4 @@
+module Control.Monad.Queue.Instances (module Control.Monad.Queue.Heap, module Control.Monad.Queue.QueueT) where
+
+import Control.Monad.Queue.Heap
+import Control.Monad.Queue.QueueT
diff --git a/Control/Monad/Queue/QueueT.hs b/Control/Monad/Queue/QueueT.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Queue/QueueT.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances, UndecidableInstances, GeneralizedNewtypeDeriving #-}
+
+
+-- | A monad transformer allowing a purely functional queue implementation (specifically, implementing the 'Queuelike' abstraction) to be used in a monadic, single-threaded fashion.
+module Control.Monad.Queue.QueueT where
+
+import Data.Queue
+import Control.Monad.State.Lazy
+import Control.Monad.Queue.Class
+import Control.Monad.RWS.Class
+import Control.Monad.Fix
+import Control.Monad.Trans(MonadIO, MonadTrans(..))
+import Control.Monad.ST.Class(MonadST)
+import Control.Monad(Monad)
+import Control.Monad.Trans.Operations
+import Data.Maybe
+
+-- | A monad transformer granting the underlying monad @m@ access to single-threaded actions on a queue.
+newtype QueueT q m a = QueueT {runQT :: StateT q m a} deriving (MonadReader r, MonadWriter w, MonadIO, MonadST s, MonadFix, Monad, MonadTrans)
+-- | A monad controlling single-threaded access to a queue.
+newtype QueueM q a = QueueM {runQM :: State q a} deriving (MonadFix, Monad)
+type PQueueT e = QueueT (PQueue e)
+type PQueueM e = QueueM (PQueue e)
+type FibQueueT e = QueueT (FQueue e)
+type FibQueueM e = QueueM (FQueue e)
+
+-- | Unwraps a queue transformer, initializing it with an empty queue.
+runQueueT :: (Monad m, Queuelike q e) => QueueT q m a -> m a
+runQueueT m = evalStateT (runQT m) empty
+
+-- | Unwraps a queue transformer, initializing it with a queue with the specified contents.
+runQueueTOn :: (Monad m, Queuelike q e) => QueueT q m a -> [e] -> m a
+runQueueTOn m xs = evalStateT (runQT m) (fromList xs)
+
+-- | Executes a computation in a queue monad, starting with an empty queue.
+runQueueM :: Queuelike q e => QueueM q a -> a
+runQueueM m = evalState (runQM m) empty
+
+-- | Executes a computation in a queue monad, starting with a queue with the specified contents.
+runQueueMOn :: Queuelike q e => QueueM q a -> [e] -> a
+runQueueMOn m xs = evalState (runQM m) (fromList xs)
+
+instance MonadState s m => MonadState s (QueueT q m) where
+	get = lift get
+	put = lift . put
+
+instance (Monad m, Queuelike q e) => MonadQueue e (QueueT q m) where
+	{-# SPECIALIZE instance (Ord e, Monad m) => MonadQueue e (PQueueT e m) #-}
+	{-# SPECIALIZE instance (Ord e, Monad m) => MonadQueue e (FibQueueT e m) #-}
+	queueInsert x = QueueT $ modify (insert x)
+	queueExtract = QueueT $ statefully (\ q -> maybe (Nothing, q) (\ (x, q') -> (Just x, q')) (extract q))
+	queueEmpty = QueueT $ gets isEmpty
+	queueDelete  = QueueT $ modify (\ q -> fromMaybe empty (delete q))
+	queuePeek = QueueT $ gets peek
+	queueSize = QueueT $ gets size
+
+instance Queuelike q e => MonadQueue e (QueueM q) where
+	{-# SPECIALIZE instance Ord e => MonadQueue e (PQueueM e) #-}
+	{-# SPECIALIZE instance Ord e => MonadQueue e (FibQueueM e) #-}
+	queueInsert x = QueueM $ modify (insert x)
+	queueExtract = QueueM $ statefully (\ q -> maybe (Nothing, q) (\ (x, q') -> (Just x, q')) (extract q))
+	queueEmpty = QueueM $ gets isEmpty
+	queueDelete  = QueueM $ modify (\ q -> fromMaybe empty (delete q))
+	queuePeek = QueueM $ gets peek
+	queueSize = QueueM $ gets size
diff --git a/Data/Queue.hs b/Data/Queue.hs
new file mode 100644
--- /dev/null
+++ b/Data/Queue.hs
@@ -0,0 +1,4 @@
+module Data.Queue (module Data.Queue.Instances, module Data.Queue.Class) where
+
+import Data.Queue.Instances
+import Data.Queue.Class
diff --git a/Data/Queue/Class.hs b/Data/Queue/Class.hs
new file mode 100644
--- /dev/null
+++ b/Data/Queue/Class.hs
@@ -0,0 +1,60 @@
+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
+
+-- | Abstracts the implementation details of a single-insertion, single-extraction queuelike structure.
+module Data.Queue.Class where
+
+import Data.List(unfoldr)
+import Control.Monad
+import Control.Monad.RWS.Class
+import Control.Monad.Trans
+import Control.Monad.State.Strict
+import Data.Maybe
+import Control.Monad.ST.Class
+
+-- | A generic type class encapsulating a generic queuelike structure, that supports single-insertion and single-extraction; this abstraction includes priority queues, stacks, and FIFO queues.  There are many minimal implementations, so each method lists the prerequisites for its default implementation.  Most implementations will implement 'empty', ('singleton' and 'merge') or 'insert', ('peek' and 'delete') or 'extract', and 'size'.
+class Queuelike q e | q -> e where
+	-- | Inserts a single element into the queue.  The default implementation uses 'merge' and 'singleton'.
+	insert :: e -> q -> q
+	insert = merge . singleton
+	-- | Inserts several elements into the queue.  The default implementation uses 'insert'.  (In some cases, it may be advantageous to override this implementation with @xs \``insertAll`\` q = q \``merge`\` `fromList` xs@.)
+	{-# INLINE insertAll #-}
+	insertAll :: [e] -> q -> q
+	insertAll = flip (foldr insert)
+	-- | Attempts to extract an element from the queue; if the queue is empty, returns Nothing.  The default implementation uses 'peek' and 'delete'.
+	extract :: q -> Maybe (e, q)
+	extract = liftM2 (liftM2 (,)) peek delete
+	-- | Gets the element that will next be extracted from the queue, if there is an element available.  The default implementation uses 'extract'.
+	peek ::  q -> Maybe e
+	peek = liftM fst . extract
+	-- | Deletes an element from the queue, if the queue is nonempty.  The default implementation uses 'extract'.
+	delete :: q -> Maybe q
+	delete = liftM snd . extract
+	-- | Constructs an empty queue.  The default implementation uses 'fromList'.
+	empty :: q
+	empty = fromList []
+	-- | Constructs a queue with a single element.  The default implementation uses 'insert' and 'empty'.
+	singleton :: e -> q
+	singleton x = insert x empty
+	-- | Constructs a queue with all of the elements in the list.  The default implementation uses 'insertAll' and 'empty'.
+	{-# INLINE fromList #-}
+	fromList :: [e] -> q
+	fromList xs = insertAll xs empty
+	-- | Gets the size of the queue.  The default implementation uses 'toList_'.
+	size :: q -> Int
+	size = length . toList_
+	-- | Checks if the queue is empty.  The default implementation uses 'peek'.
+	isEmpty :: q -> Bool
+	isEmpty = isNothing . peek
+	-- | Extracts every element from the queue.  The default implementation uses 'extract'.
+	toList :: q -> [e]
+	toList = unfoldr extract
+	-- | Extracts every element from the queue, with no guarantees upon order.  The default implementation uses 'toList'.
+	toList_ :: q -> [e]
+	toList_ = toList
+	-- | Merges two queues so that the contents of the second queue are inserted into the first queue in extraction order.  The default implementation uses 'toList' and 'insertAll'.
+	{-# INLINE merge #-}
+	merge :: q -> q -> q
+	q1 `merge` q2 = insertAll (toList q2) q1
+
+mergeAll :: Queuelike q e => [q] -> q
+mergeAll = foldr merge empty
diff --git a/Data/Queue/FibQueue.hs b/Data/Queue/FibQueue.hs
new file mode 100644
--- /dev/null
+++ b/Data/Queue/FibQueue.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE ViewPatterns, FlexibleInstances, MultiParamTypeClasses, FlexibleContexts #-}
+{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}
+
+{- |
+An alternate implementation of a priority queue based on a /Fibonacci heap/.
+
+Fibonacci heaps, while not quite as internally functional as pairing heaps, are generally less ad-hoc and may prove useful for some uses (as well as serving as a useful testbed).  A Fibonacci heap can be thought of as a lazier binomial heap, designed to better take advantage of the fact that in a lazy language a series of modification operations will likely all be computed at once, preferably as late as possible.  The Fibonacci heap supports all 'Queuelike' operations with the same time complexity as 'PQueue'.
+-}
+module Data.Queue.FibQueue (FQueue) where
+
+import Data.Queue.Class
+import Control.Monad.Array
+import Data.Tree(Tree(..))
+import Data.Maybe
+import Control.Monad
+import GHC.Exts(build)
+import Prelude hiding (getContents)
+
+data Rk e = Rk {rk :: {-# UNPACK #-} !Int, lab :: e}
+type RkTree e = Tree (Rk e)
+data FQueue e = FQueue {elts :: {-# UNPACK #-} !Int, maxRank :: {-# UNPACK #-} !Int, heap :: [RkTree e]}
+
+instance Ord e => Queuelike (FQueue e) e where
+	FQueue n1 r1 h1 `merge` FQueue n2 r2 h2 = FQueue (n1 + n2) (max r1 r2) (case (h1, h2) of
+		((treeMin -> x1):_, (treeMin -> x2):_) -> if x1 <= x2 then h1 ++ h2 else h2 ++ h1
+		(_, [])	-> h1
+		([], _)	-> h2)
+	empty = FQueue 0 0 []
+	singleton x = FQueue 1 0 [Node (Rk 0 x) []]
+	toList_ = concatMap (map lab . flatten) . heap
+	size = elts
+	peek = liftM treeMin . listToMaybe . heap
+	delete (FQueue n mR (Node (Rk _ x) ts : tss)) = Just $ rebuild (n-1) mR (mapM_ meld tss >> mapM_ meld ts)
+	delete _ = Nothing
+
+treeMin :: RkTree e -> e
+treeMin (Node (Rk _ x) _) = x
+
+{-# INLINE flatten #-}
+flatten :: Tree e -> [e]
+flatten t = build (\ c n -> flatten' c t n) where
+	flatten' c (Node x ts) n = x `c` foldr (flatten' c) n ts
+
+meldTree :: Ord e => RkTree e -> RkTree e -> RkTree e
+t1@(Node (Rk d x1) ts1) `meldTree` t2@(Node (Rk _ x2) ts2)
+	| x1 <= x2	= Node (Rk (d+1) x1) (t2:ts1)
+	| otherwise	= Node (Rk (d+1) x2) (t1:ts2)
+
+-- The use of the ArrayM monad here considerably increases readability and efficiency.
+meld :: Ord e => RkTree e -> ArrayM (Maybe (RkTree e)) ()
+meld t@(rk . rootLabel -> d) =
+	ensureSize (d+2) >> readAt d >>= maybe (writeAt d (Just t)) (\ t' -> writeAt d Nothing >> meld (t `meldTree` t'))
+
+extractMin :: Ord e => [Maybe (RkTree e)] -> (Int, [RkTree e])
+extractMin ls = case foldr exM (Nothing, 0, []) ls of (mi, rk, ts) -> maybe (0, []) ((,) rk . (:ts)) mi ; where
+	exM Nothing p = p
+	exM (Just t@(Node (Rk d x) _)) (mi, rk, ts) = let rk' = max d rk in maybe (Just t, rk', ts) 
+		(\ t'@(lab . rootLabel -> y) -> if x <= y then (Just t, rk', t':ts) else (Just t', rk', t:ts)) mi
+
+rebuild :: Ord e => Int -> Int -> ArrayM (Maybe (RkTree e)) () -> FQueue e
+rebuild n mR melder = runArrayM mR Nothing $ melder >> liftM ((\ (mR', h') -> FQueue n mR' h') . extractMin) getContents
+
+{-# INLINE mergeAllFH #-}
+mergeAllFH :: Ord e => [FQueue e] -> FQueue e
+mergeAllFH qs = case foldr merger (0, 0, return ()) qs of (n, mR, merger) -> rebuild n mR merger ; where
+		merger (FQueue n r ts) (m, mR, toMerge) = (n +  m, max r mR, mapM_ meld ts >> toMerge)
+
+{-# RULES
+	"mergeAll/FibHeap" forall (ts :: Ord e => [FQueue e]) . mergeAll ts = mergeAllFH ts
+	#-}
diff --git a/Data/Queue/Instances.hs b/Data/Queue/Instances.hs
new file mode 100644
--- /dev/null
+++ b/Data/Queue/Instances.hs
@@ -0,0 +1,7 @@
+module Data.Queue.Instances (module Data.Queue.ReverseQueue, module Data.Queue.PQueue, module Data.Queue.FibQueue, module Data.Queue.Stack, module Data.Queue.Queue) where
+
+import Data.Queue.PQueue
+import Data.Queue.FibQueue
+import Data.Queue.Stack
+import Data.Queue.Queue
+import Data.Queue.ReverseQueue
diff --git a/Data/Queue/PQueue.hs b/Data/Queue/PQueue.hs
new file mode 100644
--- /dev/null
+++ b/Data/Queue/PQueue.hs
@@ -0,0 +1,68 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
+{-# OPTIONS -fno-warn-missing-methods #-}
+{- | An efficient implementation of a priority queue.
+
+The implementation of 'PQueue' is based on a /pairing heap/, a simple and efficient implementation of a general-purpose priority queue.  'PQueue' supports 'insert', 'merge', and 'peek' in constant time, and 'extract' and 'delete' in logarithmic time.
+-}
+
+module Data.Queue.PQueue (PQueue) where
+
+import Data.Monoid
+import Data.Maybe
+import Control.Monad
+import Data.Tree
+import Data.Queue.Class
+import GHC.Exts
+
+data PHeap e = PH {elts :: {-# UNPACK #-} !Int, heap :: {-# UNPACK #-} !(Tree e)} deriving (Read, Show)
+newtype PQueue e = PQ {getQ :: Maybe (PHeap e)} deriving (Monoid, Read, Show)
+
+instance Ord e => Monoid (PHeap e) where
+	PH n1 h1 `mappend` PH n2 h2 = PH (n1 + n2) (h1 `meld` h2)
+
+instance Ord e => Queuelike (PQueue e) e where
+	singleton x = mkQ 1 (single x)
+	peek (PQ h) = fmap (rootLabel . heap) h
+	delete (PQ h) = fmap (\ (PH (n+1) (Node _ ts)) -> mkQ n (fuser ts)) h
+	isEmpty = isNothing . getQ
+	size = maybe 0 elts . getQ
+	fromList xs = case xs of	[] -> PQ Nothing
+					_ -> case foldr (\ x (n, ys) -> (n+1, single x : ys)) (0, []) xs of
+						(n, ys) -> mkQ n (fuser ys)
+	{-# INLINE toList_ #-}
+	toList_ (PQ h) = maybe [] (flatten . heap) h
+	merge = mappend
+	empty = PQ Nothing
+	xs `insertAll` q = q `merge` fromList xs
+
+{-# INLINE mkQ #-}
+mkQ :: Int -> Tree e -> PQueue e
+mkQ n t = PQ (Just (PH n t))
+
+meld :: Ord e => Tree e -> Tree e -> Tree e
+meld t1@(Node x1 ts1) t2@(Node x2 ts2) =
+	if x1 > x2 then Node x2 (t1:ts2) else Node x1 (t2:ts1)
+
+fuser :: Ord e => Forest e -> Tree e
+fuser [t] = t
+fuser l = fuser (fuser' l) where
+	fuser' (t1:t2:ts) = t1 `meld` t2 : fuser' ts
+	fuser' [t1] = [t1]
+	fuser' [] = []
+
+{-# INLINE single #-}
+single :: e -> Tree e
+single x = Node x []
+
+mergeAllPH :: Ord e => [PQueue e] -> PQueue e
+mergeAllPH qs = let (n, ts) = foldr (\ (PH n t) (m, ts) -> (n+m, t:ts)) (0, []) [ph | PQ (Just ph) <- qs] in
+	if n == 0 then PQ Nothing else mkQ n (fuser ts)
+
+{-# NOINLINE [0] flattenFB #-}
+flattenFB :: Tree a -> (a -> b -> b) -> b -> b
+flattenFB (Node x ts) c n = x `c` foldr (flip flattenFB c) n ts
+
+{-# RULES
+	"flatten" [~1] forall t . flatten t = build (flattenFB t);
+	"flattenList" [1] forall t . build (flattenFB t) = flatten t;
+	#-}
diff --git a/Data/Queue/Queue.hs b/Data/Queue/Queue.hs
new file mode 100644
--- /dev/null
+++ b/Data/Queue/Queue.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+
+-- | A basic first-in, first-out queue implementation implementing the 'Queuelike' abstraction.
+module Data.Queue.Queue (Queue) where
+
+import Data.Maybe
+import Data.Queue.Class
+import Data.Monoid
+
+data Queue e = Queue {-# UNPACK #-} !Int [e] [e] [e]
+
+instance Queuelike (Queue e) e where
+	singleton x = Queue 1 [x] [] [x]
+	empty = Queue 0 [] [] []
+	isEmpty = (==0) . size
+	size (Queue n _ _ _) = n
+	x `insert` Queue n l r a = mkQ (Queue (n+1) l (x:r) a)
+	peek (Queue _ l _ _) = listToMaybe l
+	delete (Queue (n+1) (_:l) r a) = Just (mkQ (Queue n l r a))
+	delete _ = Nothing
+
+mkQ :: Queue e -> Queue e
+mkQ (Queue n l r (a:as)) = Queue n l r as
+mkQ (Queue n l r []) = let	rot ls ~(r:rs) a = case ls of
+					[]	-> r:a
+					(l:ls)	-> l:rot ls rs (r:a)
+				l' = rot l r [] in Queue n l' [] l'
+
+instance Monoid (Queue e) where
+	mempty = empty
+	mappend = merge
diff --git a/Data/Queue/ReverseQueue.hs b/Data/Queue/ReverseQueue.hs
new file mode 100644
--- /dev/null
+++ b/Data/Queue/ReverseQueue.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FlexibleContexts, UndecidableInstances #-}
+
+-- | Generic queue wrapper to transform a min-queue into a max-queue.
+module Data.Queue.ReverseQueue (Down(..), ReverseQueue) where
+
+import Data.Queue.Class
+
+newtype Down a = Down {unDown :: a} deriving (Eq)
+
+instance Ord a => Ord (Down a) where
+	Down x `compare` Down y = case x `compare` y of
+		LT	-> GT
+		EQ	-> EQ
+		GT	-> LT
+	Down x <= Down y = x >= y
+	Down x >= Down y = x <= y
+	Down x < Down y = x > y
+	Down x > Down y = x < y
+
+-- | Wrapper around a generic queue that reverses the ordering on its elements.
+newtype ReverseQueue q e = RQ {getQueue :: q (Down e)}
+
+instance Queuelike (q (Down e)) (Down e) => Queuelike (ReverseQueue q e) e where
+	singleton x = RQ (singleton (Down x))
+	empty = RQ empty
+	fromList xs = RQ (fromList (map Down xs))
+	toList (RQ q) = map unDown (toList q)
+	toList_ (RQ q) = map unDown (toList_ q)
+	x `insert` RQ q = RQ (Down x `insert` q)
+	extract (RQ q) = fmap (\ (Down x, q) -> (x, RQ q)) (extract q)
+	peek (RQ q) = fmap unDown (peek q)
+	delete (RQ q) = fmap RQ (delete q)
+	insertAll xs (RQ q) = RQ (insertAll (map Down xs) q)
+	isEmpty (RQ q) = isEmpty q
+	RQ q1 `merge` RQ q2 = RQ (q1 `merge` q2)
diff --git a/Data/Queue/Stack.hs b/Data/Queue/Stack.hs
new file mode 100644
--- /dev/null
+++ b/Data/Queue/Stack.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
+
+-- | A basic implementation of a stack implementing the 'Queue' abstraction.
+module Data.Queue.Stack (Stack) where
+
+import Data.Monoid
+import Data.Queue.Class
+
+data Stack e = S {elts :: {-# UNPACK #-} !Int, getS :: [e]}
+
+instance Queuelike (Stack e) e where
+	insert x (S n xs) = S (n+1) (x:xs)
+	extract (S (n+1) (x:xs)) = Just (x, S n xs)
+	extract _ = Nothing
+	empty = S 0 []
+	isEmpty = null . getS
+	size = elts
+	toList = getS
+	S n1 s1 `merge` S n2 s2 = S (n1 + n2) (s2 ++ s1)
+
+instance Monoid (Stack e) where
+	mempty = empty
+	mappend = merge
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,16 @@
+Copyright (c) 2008, Louis Wasserman
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the 
+documentation and/or other materials provided with the distribution.
+    * The name of Louis Wasserman may not be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+OF SUCH DAMAGE.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/pqueue-mtl.cabal b/pqueue-mtl.cabal
new file mode 100644
--- /dev/null
+++ b/pqueue-mtl.cabal
@@ -0,0 +1,16 @@
+
+name:		pqueue-mtl
+version:	1.0
+synopsis:	Fully encapsulated monad transformers with queuelike functionality.
+description:	Contains several implementations of data structures implementing a /single-in, single-out/ paradigm, and implements monad transformers for their safe use.  The monad transformer part of the library includes tools to fully encapsulate single-threaded use of a priority queue in a monad, including an array-based heap implementation.
+tested-with:	GHC
+category:	Monads, Algorithms
+license:	BSD3
+license-file:	LICENSE
+author:		Louis Wasserman
+maintainer:	wasserman.louis@gmail.com
+build-Depends:	base, ghc-prim, mtl, containers, stateful-mtl, MaybeT
+build-type:	Simple
+Exposed-modules:Control.Monad.Queue, Control.Monad.Queue.Instances, Control.Monad.Queue.Class, Control.Monad.Queue.Heap, Control.Monad.Queue.QueueT, Data.Queue, Data.Queue.PQueue, Data.Queue.FibQueue, Data.Queue.Class, Data.Queue.Instances, Data.Queue.Stack, Data.Queue.Queue, Data.Queue.ReverseQueue
+ghc-options:
+
