
Am Freitag, 17. Oktober 2008 08:58 schrieb Jamie McCloskey:
Hi everyone, I have just started learning Haskell, it is a very interesting language. As a first project, I am building a brainfuck interpreter, but have hit a stumbling block: IO. My program source is located at http://hpaste.org/11219
My program handles the state of a brainfuck program by passing State(lists of ints) objects around. When I added my getIn fuction, however, it needed to return an IO State object. This broke the run function, as it returned a State. No problem, I thought, and changed run to return IO State. This broke my exec function, which calls run on each element in a list.
As exec passes on the state returned by the run function to itself, it needs to take an IO State. This causes problems in the loop function, which calls exec on a subprogram. Because exec now takes IO State, loop also needs to. However, loop is called by run, so now run needs to take IO State. Now, all functions called by run need to take IO State.
All this creates a whole load of functions with IO, even though it should not be necessary. What I would like to know, is how I can avoid this, possibly by modifying exec to just take a State.
exec [] st = return st exec (x:xs) st = do newSt <- run x st exec xs newSt or exec (x:xs) st = run x st >>= exec xs Once you're doing input or output, you're in IO, so run and exec must have type a -> b -> IO c, getIn and putOut must also live in IO, everything else needn't.
Whew! What a long-winded explanation!
Any ideas?
--Jamie
P.S. Please ignore my long-winded list iteration functions -- I'm working on a cleaner version.
Probably the tidiest (as if that was a criterion for a brainfuck interpreter) would be to rename your State to ProgramState (or whatever) and write the interpreter in StateT ProgramState IO , you'd have run :: Operator -> StateT ProgramState IO () run Add = modify myAdd run Minus = ... run Input = do n <- lift $ readLn modify (inHelper n) and exec = mapM_ run HTH, Daniel