HORIZON HASKELLDocslts/ghc-10.0.xfc4e5982026-10-11Search names, modules, packages, or :: a typeCtrl K

GHC 10.0.0.20260917 · lts/ghc-10.0.x · fc4e598 · 2026-10-11

Moduleghc-internal-10.0.0Haskell2010

GHC.Internal.Control.Monad.Fix

Monadic fixpoints.

For a detailed discussion, see Levent Erkok's thesis, Value Recursion in Monadic Computations, Oregon Graduate Institute, 2002.

  • 2 classes
  • 2 values
classclass Monad m => MonadFix (m :: Type -> Type) where
#

Monads having fixed points with a 'knot-tying' semantics. Instances of MonadFix should satisfy the following laws:

Purity

mfix (Control.Monad.return . h) = Control.Monad.return (fix h)

Left shrinking (or Tightening)

mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y)

Sliding

mfix (Control.Monad.liftM h . f) = Control.Monad.liftM h (mfix (f . h))

, for strict

h

.

Nesting

mfix (\x -> mfix (\y -> f x y)) = mfix (\x -> f x x)

This class is used in the translation of the recursive do notation supported by GHC and Hugs.

Methods

  • mfix :: (a -> m a) -> m a

    The fixed point of a monadic computation. mfix f executes the action f only once, with the eventual output fed back as the input. Hence f should not be strict, for then mfix f would diverge.

Instances24MonadFix, …
  • MonadFix NonEmptyDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix IdentityDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix FirstDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix LastDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix DownDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix DualDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix ProductDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix SumDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix Par1Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix MaybeDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix QDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix

    If the function passed to mfix inspects its argument, the resulting action will throw a FixIOException.

  • MonadFix SoloDefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix IODefined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix []Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • Monoid a => MonadFix (Tuple2 a)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix (ST s)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix (Either e)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix (ST s)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix f => MonadFix (Ap f)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix f => MonadFix (Alt f)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix f => MonadFix (Rec1 f)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix ((->) r)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • (MonadFix f, MonadFix g) => MonadFix (f :*: g)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
  • MonadFix f => MonadFix (M1 i c f)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix
valuefix :: (a -> a) -> a
#

fix f is the least fixed point of the function f, i.e. the least defined x such that f x = x.

When f is strict, this means that because, by the definition of strictness, f ⊥ = ⊥ and such the least defined fixed point of any strict function is ⊥.

Examples

We can write the factorial function using direct recursion as

Example1 expression
let fac n = if n <= 1 then 1 else n * fac (n-1) in fac 5120

This uses the fact that Haskell’s let introduces recursive bindings. We can rewrite this definition using fix,

Instead of making a recursive call, we introduce a dummy parameter rec; when used within fix, this parameter then refers to fix’s argument, hence the recursion is reintroduced.

Example1 expression
fix (\rec n -> if n <= 1 then 1 else n * rec (n-1)) 5120

Using fix, we can implement versions of repeat as fix . (:) and cycle as fix . (++)

Example1 expression
take 10 $ fix (0:)[0,0,0,0,0,0,0,0,0,0]
Example1 expression
map (fix (\rec n -> if n < 2 then n else rec (n - 1) + rec (n - 2))) [1..10][1,1,2,3,5,8,13,21,34,55]
Implementation Details

The current implementation of fix uses structural sharing

fix f = let x = f x in x

A more straightforward but non-sharing version would look like

fix f = f (fix f)
valuefixIO :: (a -> IO a) -> IO a
#

The implementation of Control.Monad.Fix.mfix for IO.

This operation may fail with:

Examples

the IO-action is only executed once. The recursion is only on the values.

Example1 expression
take 3 <$> fixIO (\x -> putStr ":D" >> (:x) <$> readLn @Int):D2[2,2,2]

If we are strict in the value, just as with Data.Function.fix, we do not get termination:

Example1 expression
fixIO (\x -> putStr x >> pure ('x' : x))* hangs forever *

We can tie the knot of a structure within IO using fixIO:

data Node = MkNode Int (IORef Node)

foo :: IO ()
foo = do
  p <- fixIO (p -> newIORef (MkNode 0 p))
  q <- output p
  r <- output q
  _ <- output r
  pure ()

output :: IORef Node -> IO (IORef Node)
output ref = do
  MkNode x p <- readIORef ref
  print x
  pure p
Example1 expression
foo000

Feedback for Arrow

1 declaration
classclass Arrow a => ArrowLoop (a :: Type -> Type -> Type) where
#

The loop operator expresses computations in which an output value is fed back as input, although the computation occurs only once. It underlies the rec value recursion construct in arrow notation. loop should satisfy the following laws:

extension

loop (arr f) = arr (\ b -> fst (fix (\ (c,d) -> f (b,d))))

left tightening

loop (first h >>> f) = h >>> loop f

right tightening

loop (f >>> first h) = loop f >>> h

sliding

loop (f >>> arr (id *** k)) = loop (arr (id *** k) >>> f)

vanishing

loop (loop f) = loop (arr unassoc >>> f >>> arr assoc)

superposing

second (loop f) = loop (arr assoc >>> second f >>> arr unassoc)

where

assoc ((a,b),c) = (a,(b,c))
unassoc (a,(b,c)) = ((a,b),c)

Methods

  • loop :: a (b, d) (c, d) -> a b c
        ╭──────────────╮
      b │     ╭───╮    │ c
    >───┼─────┤   ├────┼───>
        │   ┌─┤   ├─┐  │
        │ d │ ╰───╯ │  │
        │   └───<───┘  │
        ╰──────────────╯
Instances2ArrowLoop
  • MonadFix m => ArrowLoop (Kleisli m)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix

    Beware that for many monads (those for which the >>= operation is strict) this instance will not satisfy the right-tightening law required by the ArrowLoop class.

  • ArrowLoop (->)Defined in ghc-internal-10.0.0 · GHC.Internal.Control.Monad.Fix