3 ms·
From where I see it, that belongs in `a`. It's your parsing result.
by mixedCase 3y ago
From where I see it, that belongs in `a`. It's your parsing result.
- amluto 3y agoWait, so I’m supposed to write a parser that (maybe) returns a tuple containing (result of parsing, where it came from) and (rest of string)? Why? I don’t know if it has a formal name, but I’ve generally imagined that a lot of the point of a strong typing system is to make representing valid values straightforward and to make representing invalid values impossible. This is the opposite — valid values are nontrivial — I would have to encode the position by hand, which makes any use of, say, fmap quite messy because I need to either define a more complicated functor (and maybe make consuming a subset of the parse tree and tracking that fact impossible) or manually pass position context through. And invalid values are all to easy to represent: the context could fail to match the returned string length or the returned string could fail to be a suffix.
- mrkeen 3y ago> I would have to encode the position by hand ... or manually pass position context through. You're having a /r/restofthefuckingowl moment, and I understand the reaction, but calm down :D There is a little wiggle-room for error, down at the 'unit' level. Here's a parser (based on the above Parser type) which consumes input as long as its predicate matches: parseWhile :: (Char -> Bool) -> Parser String parseWhile pred = P $ \s -> do let some = takeWhile pred s rest = dropWhile pred s Just (some, rest) It's verbose, and maybe there's a bug in it? (Side note: it also needs to step through s twice, so it's dumb). Here's a more compact version without the 2 * work: parseWhile' :: (Char -> Bool) -> Parser String parseWhile' pred = P $ Just . span pred No type-systemy category-theoretical nonsense will stop me from getting a boolean the wrong way around. Maybe I accidentally implemented skipWhile or parseUntil without realising. So what's the point? * You build bigger parts out of smaller parts * Here's the actual parser for my if-then-else expression in my language: parseIfThenElse :: Parser ParseState (Expr Untyped ByteString) parseIfThenElse = do p <- token TIf *> parseExpr t <- token TThen *> parseExpr f <- token TElse *> parseExpr pure $ IfThenElse Untyped p t f No manual plumbing or passing in the above code. What about one step up? Here's code which calls the above: parseNonApply :: Parser ParseState (Expr Untyped ByteString) parseNonApply = parseLet <|> parseIfThenElse <|> parseLambda <|> parseTerm <|> parseNegated <|> parseShown <|> parseErr <|> parseParen