Using Cont to acquire values from the future and the past

后端 未结 2 1230
自闭症患者
自闭症患者 2021-02-02 13:02

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         


        
相关标签:
2条回答
  • 2021-02-02 13:29

    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)
    
    0 讨论(0)
  • 2021-02-02 13:32

    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.

    0 讨论(0)
提交回复
热议问题