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)
Being terribly lazy with this answer since I'm not comfortable with Cont, but is MonadFix perhaps what you're looking for? State is an instance, though not Cont, and it lets you do things that look like (using "recursive do" notation):
{-# LANGUAGE DoRec #-}
parseInst str = do
rec ctl <- parseInstructionsLinkingTo ctl str
This was the solution I discovered for my actors library: we want a spawn operation that returns the spawned actor's mailbox, but then how can we launch mutually-communicating actors? Or an actor with access to its own mailbox?
With a suitable MonadFix instance we can do:
fork3 = do
rec mb1 <- spawn $ actorSpamming mb2 mb3
mb2 <- spawn $ actorSpamming mb1 mb2
mb3 <- spawn $ actorSpamming mb2 mb3
send "go" mb1
Hope above gives you ideas.