I\'m writing a brainfuck interpreter in Haskell, and I came up with what I believe to be a very interesting description of a program:
data Program m = Instructio
Forwards traveling state with a continuation monad looks like this:
Cont (fw -> r) a
Then the type of the argument to cont
is
(a -> fw -> r) -> fw -> r
So you get a fw
passed in from the past which you have to pass on to the continuation.
Backwards traveling state looks like this:
Cont (bw, r) a
Then the type of the argument to cont
is
(a -> (bw, r)) -> (bw, r)
I.e. you get a bw
from the continuation which you have to pass on to the past.
These can be combined into one continuation monad:
Cont (fw -> (bw, r)) a
There's a catch when applying this to your parser, because toProgramStep
builds the program in reverse, so the list of ']' points is the forward state, and the list of '[' points is the backward state. Also, I got lazy and skipped the Maybe part, which should catch the pattern matching errors in openBrace
and closeBrace
.
type ParseState = Cont ([TapeP] -> ([TapeP], TapeP))
toProgram :: String -> TapeP
toProgram = snd . ($ []) . (`runCont` (\a _ -> ([], a))) . toProgramStep
openBrace :: ParseState TapeP -> ParseState TapeP
openBrace mcontinue = do
continue <- mcontinue
cont $ \k (break:bs) -> let (cs, r) = k (loopControl continue break) bs in (continue:cs, r)
closeBrace :: ParseState TapeP -> ParseState TapeP
closeBrace mbreak = do
break <- mbreak
cont $ \k bs -> let (continue:cs, r) = k (loopControl continue break) (break:bs) in (cs, r)