In your case, this is a strictness problem causing a stack overflow. One very easy way to find such problems is to use the deepseq library . This adds a few functions that allow you to fully appreciate the value (which is better than seq , which is only one level down). The key function force :: NFData a => a -> a . This takes a value, fully evaluates it, and returns it.
It works only for types that implement a class of type NFData . Fortunately, there is a haskell template macro in deepseq-th library : deriveNFData . This is used with your own data types, e.g. deriveNFData ''BfMachine .
To use, you put force $ in front of your functions, which may have strictness problems (or liftM force $ for monadic functions). For example, with your code, I put it before step , as it was a key function in the file:
{-# LANGUAGE TemplateHaskell #-} import Data.Char import Debug.Trace import Control.DeepSeq import Control.DeepSeq.TH import Control.Monad (liftM) type Stack = [Int] data BfMachine = BfMachine { program :: String , pc :: Int , stack :: Stack , sp :: Int } deriving Show deriveNFData ''BfMachine setElem :: [Int] -> Int -> Int -> [Int] setElem list n value = map (\(i, v) -> if i == n then value else v) (zip [0..] list) step :: BfMachine -> IO (BfMachine) step m@(BfMachine { program = program, pc = pc, stack = stack, sp = sp }) = liftM force $ case program !! pc of '-' -> return m { pc = pc + 1, stack = setElem stack sp ((stack !! sp) - 1) } '+' -> return m { pc = pc + 1, stack = setElem stack sp ((stack !! sp) + 1) } '<' -> return m { pc = pc + 1, sp = sp - 1 } '>' -> return m { pc = pc + 1, sp = sp + 1 } '[' -> return $ if stack !! sp /= 0 then m { pc = pc + 1 } else m { pc = (findNextBracket program $ pc + 1) + 1 } ']' -> return m { pc = findPrevBracket program $ pc - 1 } '.' -> do putChar $ chr $ stack !! sp return m { pc = pc + 1 } ',' -> do c <- getChar let s' = setElem stack sp $ ord c in return m { stack = s', pc = pc + 1 } a -> return m { pc = pc + 1 } findNextBracket :: String -> Int -> Int findNextBracket program pos = case program !! pos of '[' -> findNextBracket program $ (findNextBracket program $ pos + 1) + 1 ']' -> pos x -> findNextBracket program (pos + 1) findPrevBracket :: String -> Int -> Int findPrevBracket program pos = case program !! pos of ']' -> findPrevBracket program $ (findPrevBracket program $ pos - 1) - 1 '[' -> pos x -> findPrevBracket program (pos - 1) isFinished :: BfMachine -> Bool isFinished m@(BfMachine { program = p, pc = pc }) | pc == length p = True | otherwise = False run :: BfMachine -> IO () run m = do if isFinished m then return () else do m <- step m run m fib = ">++++++++++>+>+[ [+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[ [-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<- [>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>> ]<<< ] This program doesn't terminate; you will have to kill it. Daniel B Cristofani (cristofdathevanetdotcom) http://www.hevanet.com/cristofd/brainfuck/" main = run BfMachine { program = fib , pc = 0, stack = replicate 1024 0, sp = 0 }
This actually solves the problem - even after a few minutes it did not crash, and the memory usage is only 3.2 MB.
You can stick to this solution or try to find where the problem is real rigor (as it makes everything rigorous). You do this by removing the force from the step function and trying it on the helper functions that it uses (e.g. setElem , findPrevBacket , etc.). It turns out that setElem is the culprit, putting force in front of this function also solves the strictness problem. I suppose this is because if on a lambda map means that most of the values ββnever need to be evaluated on the list and possibly create huge tricks as the program continues.