In Haskell, IORef helps us get imperative code that runs in the IO monad. The ST variant allows us to use mutable computations purely.

-- Imperative version of the factorial.
import Data.IORef
import Control.Monad.Loops
 
factorial :: Int -> IO Int
factorial n = do
  accumulator <- newIORef 1
  number <- newIORef n
  whileM_ (readIORef number >>= (\i -> return $ i > 0)) $ do
    i' <- readIORef number
    a' <- readIORef accumulator
    writeIORef accumulator (a' * i')
    writeIORef number (i' - 1)
  a' <- readIORef accumulator
  return a'
 

There are ways of making this less ugly and more C-like (see CStyle).

Tags: Haskell.