{-# LANGUAGE GeneralizedNewtypeDeriving #-}moduleControl.Monad.Trans.UnionFind(UnionFindT,runUnionFind,Point,fresh,repr,descriptor,union,equivalent)whereimportControl.Applicative(Applicative)importControl.Monad.Trans.Class(MonadTrans(..))importControl.Monad.Trans.State(StateT(..),evalStateT)importData.UnionFind.IntMap(Point)importqualifiedControl.Monad.Trans.StateasStateimportqualifiedData.UnionFind.IntMapasUF-- | A monad transformer that adds union find operations.---- The @p@ parameter is the type of points. Uses the-- "Data.UnionFind.IntMap" as the underlying union-find-- implementation.newtypeUnionFindTpma=UnionFindT{unUnionFindT::StateT(UF.PointSupplyp)ma}deriving(Functor,Applicative,Monad,MonadTrans)runUnionFind::Monadm=>UnionFindTpma->marunUnionFind=(`evalStateT`UF.newPointSupply).unUnionFindTswap::(a,b)->(b,a)swap(x,y)=(y,x)-- | Create a new point with the given descriptor. The returned is-- only equivalent to itself.---- Note that a 'Point' has its own identity. That is, if two points-- are equivalent then their descriptors are equal, but not vice-- versa.--fresh::Monadm=>p->UnionFindTpm(Pointp)freshx=UnionFindT.StateT$return.swap.flipUF.freshx-- | /O(1)/. @repr point@ returns the representative point of-- @point@'s equivalence class.repr::Monadm=>Pointp->UnionFindTpm(Pointp)repr=UnionFindT.State.gets.flipUF.repr-- | Return the descriptor of the descriptor::Monadm=>Pointp->UnionFindTpmpdescriptor=UnionFindT.State.gets.flipUF.descriptor-- | Join the equivalence classes of the points. The resulting-- equivalence class will get the descriptor of the second argument.union::Monadm=>Pointp->Pointp->UnionFindTpm()unionp1p2=UnionFindT.State.modify$\x->UF.unionxp1p2-- | Test if the two elements are in the same equivalence class.-- -- @-- liftA2 (==) (repr x) (repr y)-- @equivalent::Monadm=>Pointp->Pointp->UnionFindTpmBoolequivalentp1p2=UnionFindT.State.gets$\x->UF.equivalentxp1p2