Prim's Lazy Minimum Spanning Tree Algorithm in Haskell (Project Euler# 107)
I would separate the looping queue logic from the rest. A general implementation of unrollM necessitates a state monad here.

import Control.Monad.State
import Control.Monad.Loops

unrollM :: (Monad m, Ord a) =&gt; (a -&gt; m [a]) -&gt; [a] -&gt; m [a]
unrollM f = step . (Heap.fromList :: Ord a =&gt; [a] -&gt; Heap.MinHeap a) where
  step queue = case Heap.view queue of
    Nothing -&gt; pure []
    Just (x, queue') -&gt; do
      as &lt;- f x
      (x:) &lt;$&gt; step (foldl (flip Heap.insert) queue' as)

minimumSpanningTreeEdgeSum :: Array (Int, Int) Int -&gt; Int
minimumSpanningTreeEdgeSum adj = sum $ map fst $ (`evalState` Set.singleton 0) $ unrollM minimumSpanningTree'
  [(adj!(0,a),(0, a)) | a &lt;- [1..dim-1], adj ! (0,a) &gt; 0] where
  minimumSpanningTree' :: (Int, (Int, Int)) -&gt; State (Set.Set Int) [(Int, (Int, Int))]
  minimumSpanningTree' (weight, (from, to)) = firstM (gets . Set.notMember) [from, to] &gt;&gt;= \case
    Nothing -&gt; pure []
    Just nextVertex -&gt; do
      modify $ Set.insert nextVertex
      filterM (gets . Set.notMember . fst . snd) $ filter ((&gt;0) . fst)
        [ (adj ! (i,j), (i, j))
        | a &lt;- [0..dim-1]
        , let [i,j] = sort [nextVertex, a]
        ]