Using Cont to acquire values from the future and the past

旧时模样 提交于 2019-12-02 21:36:00

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!