So one of the things that happens is heavier reliance on recursion, the values passed to the function can change like a variable, but they're still parameters. Which leads to encapsulating values in a state monad, and then passing the monadic values around.

What is a monad? That is where most people get very confused. Mathematically a monad is different than how it is implemented in Haskell! In Haskell a monad is really just a data type pointer. So you have something like IO Integer and it's a pointer to an Integer. Unfortunately the IO monad has no good constructor, you need to use IOArray, IORef, TVar or some other monad to create a variable. For now let's stick to using IORef since it's intended for this.

module Main where

import Data.IORef

main = do

-- a new variable called var

var <- newIORef (1::Integer)

-- the contents of var

a <- readIORef var

-- add one to var

modifyIORef var (+1)

-- the contents of var

b <- readIORef var

-- set var to 3

writeIORef var 3

-- the contents of var

c <- readIORef var

putStrLn $ show a

putStrLn $ show b

putStrLn $ show c

This is how variables are done in Haskell, with the following caveat: in general IORef isn't thread safe. So you might rather use something like:

module Variables (Variable, newVar, setVar, getVar, modVar, showVar) where

import Control.Monad

import Control.Concurrent

import Control.Concurrent.STM

type Variable a = TVar a

-- initialize a new variable

newVar :: a -> IO (Variable a)

newVar value = atomically $ newTVar value

-- get the value of a variable

getVar :: Variable a -> IO a

getVar pntr = atomically $ do

value <- readTVar pntr

return value

-- set the value of a variable

setVar :: Variable a -> a -> IO a

setVar pntr value = atomically $ do

writeTVar pntr value

return value

-- apply a function to a variable

modVar :: Variable a -> (a -> a) -> IO a

modVar pntr fn = atomically $ do

value1 <- readTVar pntr

let value2 = fn value1

writeTVar pntr value2

return value2

-- a show function for a variable (for GHCI)

showVar :: (Show a) => Variable a -> IO ()

showVar pntr = do

value <- atomically $ readTVar pntr

putStrLn $ show value

This is thread safe on top of TVar. Variables.hs

So using this we'd have:

module Main where

import Variables

main = do

-- a new variable called var

var <- newVar (1::Integer)

-- the contents of var

a <- getVar var

-- add one to var

modVar var (+1)

-- the contents of var

b <- getVar var

-- set var to 3

setVar var 3

-- the contents of var

c <- getVar var

putStrLn $ show a

putStrLn $ show b

putStrLn $ show c

Which is almost the same as using IORef, but thread safe.