{-# LANGUAGE TypeFamilies, NoMonomorphismRestriction, MultiParamTypeClasses, FlexibleInstances,
             NoImplicitPrelude, FlexibleContexts #-}

module Control.RMonad.Fix (RMonadFix (..), fix) where

import Control.RMonad.Prelude

import Control.Monad.Fix (fix)
import qualified Control.Monad.Fix as M

import Data.Set (Set)
import qualified Data.Set as Set
import Data.Suitable

class RMonad m => RMonadFix m where
    mfix :: Suitable m a => (a -> m a) -> m a

instance RMonadFix Maybe where
    mfix = M.mfix

instance RMonadFix [] where
    mfix = M.mfix

instance RMonadFix IO where
    mfix = M.mfix

instance RMonadFix ((->) r) where
    mfix = M.mfix

instance RMonadFix Set where
    mfix f = withResConstraints $ \SetConstraints ->
             case Set.minView (fix (f . Set.findMin)) of
               Nothing -> Set.empty
               Just (x, _) -> Set.insert x (mfix (Set.deleteMin . f))