Hello all,<br><br>I just released two new packages on Hackage, stateful-mtl and pqueue-mtl.<br><br>Stateful-mtl provides an ST monad transformer, several useful operations on generic monad transformers, and a monad transformer intended to cleanly externally wrap operations on a mutable array (including resizing operations).&nbsp; It provides wrappers to generic MArray instances, an &quot;array&quot; based on an IntMap, and a specialized transformer that completely wraps what is essentially a pared-down STArray into a monadic interface that doesn&#39;t mention ST at all.<br>
<br>pqueue-mtl provides implementations of several structures supporting a generic &#39;single-in, single-out&#39; paradigm (encapsulated in a typeclass named Queuelike), including stacks, queues, and several implementations of priority queues, including primarily a PQueue structure (in Data.Queue.PQueue) based on a pairing heap.&nbsp; In addition, the package provides monad transformers encapsulating single-threaded access to a Queuelike structure, and provides a fully encapsulated array-backed heap implementation (using the array transformers from stateful-mtl).<br>
<br>The primary motivation for all this was to improve elegance of graph algorithms.&nbsp; The following is an implementation of a shortest-path algorithm based on the fgl library that returns an IntMap mapping each node to its parent in a shortest-path tree:<br>
<br><span style="font-family: courier new,monospace;">type DijkstraM gr a b = IntMapT (Node, b) (PQueueT (Edge :-&gt; b) (State (gr a b)))</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">expand :: (Num b, Ord b, MonadQueue (Edge :-&gt; b) m) =&gt; b -&gt; Context a b -&gt; m ()</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">expand d cxt = let x = node&#39; cxt -- node being expanded</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; in queueInsertAll [(y, x) :-&gt; (d + w) | (y, w) &lt;- lsuc&#39; cxt]</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">dijkstraM :: (Graph gr, Num b, Ord b) =&gt; DijkstraM gr a b ()</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">dijkstraM = execMaybeT $ forever $ do</span>&nbsp; <span style="font-family: courier new,monospace;">-- this line repeats a monadic operation until a pattern match fails</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; False &lt;- gets isEmpty</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; Just ((v, w) :-&gt; d) &lt;- queueExtract</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; statefully (match v) &gt;&gt;=? \ c -&gt; writeAt v (w, d) &gt;&gt; expand d c -- performs an action if the match does not return Nothing</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">dijkstra :: (Graph gr, Num b, Ord b) =&gt; gr a b -&gt; Node -&gt; IntMap (Node, b)</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">dijkstra g v = evalState (runQueueTOn (execIntMapT_ dijkstraM) [(v, v) :-&gt; 0]) g</span><br style="font-family: courier new,monospace;"><br>As an imperative programmer for many years, this is pretty much the most intuitive implementation of Dijkstra&#39;s algorithm that I&#39;ve seen.&nbsp; Let me know what you think.<br>
<br clear="all">Louis Wasserman<br><a href="mailto:wasserman.louis@gmail.com">wasserman.louis@gmail.com</a><br>