Debugging a stack overflow in haskell -
i'm new haskell , functional programming , have program works overflows stack after few seconds. question is, should here? how can @ least hint of occurs, print stack or anything?
the program slow when running in ghci :trace stack overflow not occur. not occur runhaskell eat more , more memory. error when compiling ghc , executing.
in case, strictness problem causing stack overflow. 1 easy way find such issues using deepseq library. adds few functions allow evaluate value (which better seq
, goes 1 level down). key function force :: nfdata => -> a
. takes value, evaluates it, , returns it.
it works on types implement nfdata
type class though. luckily, there template haskell macro in deepseq-th library: derivenfdata
. used own data types, eg derivenfdata ''bfmachine
.
to use, put force $
in front of functions may having strictness problems (or liftm force $
monadic functions). eg code, put in front of step
, since key function in 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 == n 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 m { pc = pc + 1 } else m { pc = (findnextbracket program $ pc + 1) + 1 } ']' -> return m { pc = findprevbracket program $ pc - 1 } '.' -> putchar $ chr $ stack !! sp return m { pc = pc + 1 } ',' -> c <- getchar let s' = setelem stack sp $ ord c in return m { stack = s', pc = pc + 1 } -> 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 = if isfinished m return () else m <- step m run m fib = ">++++++++++>+>+[ [+++++[>++++++++<-]>.<++++++[>--------<-]+<<<]>.>>[ [-]<[>+<-]>>[<<+>+>-]<[>+<-[>+<-[>+<-[>+<-[>+<-[>+<- [>+<-[>+<-[>+<-[>[-]>+>+<<<-[>+<-]]]]]]]]]]]+>>> ]<<< ] program doesn't terminate; have 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 solves problem - after few minutes running, hasn't crashed , memory usage 3.2mb.
you can stick solution, or try find real strictness problem (as makes strict). removing force step
function, , trying on helper functions uses (eg setelem
, findprevbacket
, etc). turns out setelem
culprit, putting force
in front of function solves strictness problem. i'm guessing because if
in map lambda means values never have evaluated in list, , possibly build huge thunks program continues.
Comments
Post a Comment