![]() Also, the intended usage for a user state is to maintain state that's necessary for the parser to decide how to perform the actual parse. A parser written in this form will be harder to understand and modify than the standard approach. However, both these approaches of building up a state while parsing are weird and non-standard. (Left err, _) -> error $ "parse error: " ++ show err For example: type Parser'' = ParsecT String () ( Board)Ĭase runState (runParserT moves'' () "" str) board0 of ![]() (State Board) monad transformer stack with a standard State layer. Here, loadGame' runs the parser on the user state with moves' and then uses a getState call to fetch the final board.Ī nearly equivalent solution, since ParsecT is a monad transformer, is to create a ParsecT. Will generate the final game state: loadGame' :: String -> BoardĬase runParser (moves' > getState) ,] "" str of Now, the act of simply parsing a list of moves: moves' :: Parser' () Note that move''s return type is () because its action is implemented as a side-effect on the user state. Define a parser with a Board user state: type Parser' = Parsec String BoardĪnd then a parser for a single move that modifies the user state: move' :: Parser' () ![]() To actually thread a state through a set of parsers, you can use the "user state" feature of Parsec. Moves1 = foldl' turn board0 sepBy move (char ',')īut this won't generalize too well if you have multiple parsers that need to operate on a single underlying state. In this particular case, given the definition of turn above, we can parse directly into a Board by incorporating the fold from the game function into the parser: moves1 :: Parser Board If you really want to build up the state during the parse, there are several ways to do it. This should be your go-to solution for this kind of problem: parse first into a simple stateless intermediate form, and then process this intermediate form in a "stateful" computation. Left err -> error $ "parse error: " ++ show err ~ pĪnd then connect them together in a loadGame function: loadGame :: String -> Board We can separate the parser, which just generates a list of moves: data Move = Move Piece Int Intįrom the functions that regenerate the game state: board0 :: Board Into a board ,] representing the game state: O | X | Let's say we have a tic-tac-toe board: data Piece = X | O | N deriving (Show) The simplest way to incorporate a "state" into a parser is not to do it at all.
0 Comments
Leave a Reply. |
Details
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |