-
Notifications
You must be signed in to change notification settings - Fork 51
Compactable
and Filterable
instances
#85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for opening a PR, @3ddyy! I've stepped through the code and commented on a few things which stood out to me. While I've used purescript-parsing
before, I perform general maintenance on this library and am not a contributing developer myself. With that in mind I'd like to hear from another maintainer before merging.
I'd also appreciate a quick opinion from @LiamGoodacre as the author of purescript-filterable
about these instances (if you have a moment, Liam!).
In addition, while I can see what this is adding to the library, I'd appreciate hearing if you have any idea what possible drawbacks these instances may have @3ddyy. For example, do these have worse error messages compared to writing a parser out if the instances didn't exist? If you aren't aware of any drawbacks that's fine, I'm just curious.
src/Text/Parsing/Parser.purs
Outdated
, right: do | ||
state <- get | ||
p1 >>= case _ of | ||
Left r -> put state *> fail "Parse returned Left" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here (and elsewhere) the state <- get
bind occurs ahead of the case statement, and then the state
is only used in one branch. Is there any reason not to only perform the get in the branches where it is required? ie.
{ ...
, right: p1 >>= case _ of
Left _ -> do
state <- get
put state *> fail "Parse returned Left"
}
For that matter, do you mind briefly letting me know the reason for getting and then putting the state? Is there any reason to not just call fail
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point in getting the state is that it's done before the parser p1
is run. The way you changed it makes it so that the getting and setting happen right after eachother, which would be the same as just fail
ing right away and not doing anything else. The reason i'm getting the state before running the parser is that when the parser fails, I believe the right move is to error at the position from before the parser. Let's say you parse "34" with digit *> filter (_ == 1) digit
(digit
is from Test.Main and just parses a single digit 1-9). It will error at position 2, as it should. (Reason being that the character 4
is what's wrong). If we do not get the state beforehand and set it when erroring, the error would report position 3, which would be incorrect. The reason for grabbing the whole state is that if the result is filtered away, I want the parser to act as if it wasn't run at all, except for erroring of course. It might be better to just get the position though, and then fail with that position? (not altering other parts of the state.) Then it would be possible to decide whether to have it backtrack or not when using it with <|>
, simply by putting try
in front of it or not.
When it comes to error messages, they are a bit worse than what you would get otherwise. For this reason, I've provided two functions in |
Yep, when |
Just waiting on an opinion here: Is it best to reset the parser entirely when something is filtered away (act like it never ran, but just failed instantly)? Or is it better to just reset the position, and allow people to backtrack manually using |
Hi, thanks for this PR @artemisSystem ! Sorry this has been open for ten months. I hope you're still interested in this. I think I understand the problem you're trying to solve here, and it's an important problem, and this is a good solution. The problem is that sometimes we want to fail in the parsing monad for reasons not directly related to grammar, but more related to “validation.” And this is a very good idea! This is exactly the way we should be thinking, according to Alexis King. I tried to solve this problem myself once with these three little helper combinators. Your solution considers something which I hadn't thought about, which is that if we're going to fail as a result of parsing a thing, then we should backtrack the parsing state and report the error at the beginning of the thing. I would like to merge this, or something like it, but I want to talk first. Your functions Your implementations for So I wonder if these |
This is such a good question and I don't know the answer. We have to think about this. |
Oh your linked issue has a lot more discussion about this, reading now. |
Being purely pedantic, it's actually been 22 months, but no worries about the time since i'd completely forgotten about this PR myself 😁 (and the ball's been in my court). I think the original reason i submitted this PR was just the fact that a lawful From what i remember, both of the implementations of the extra functions ( I think I'm unlikely to spend more time on this in the near future, but you're welcome to work off my changes if you want to. I see that this PR is from back in the psc-package days, so it might be best if this PR is rebased and re-opened anyway P.S. There's some more discussion in #84 in case you haven't seen that. My opinion is that it's fine to have P.P.S.
I think the latter makes more sense to best align with the rest of the package, which i think Liam is agreeing with via the thumbs up reaction. |
Yeah I will, there are good ideas in here. Also some time in the last 22 months filterable has moved from LiamGoodacre's Github to https://github.com/purescript/purescript-filterable , so that changes things too. |
Closing this in favor of #212, see #84 (comment) |
Fixes #84
What does this pull request do?
Implements
Compactable
andFilterable
instances forParserT
Where should the reviewer start?
instance implementations in src/Text/Parsing/Parser.purs
How should this be manually tested?
Tests provided in test/Main.purs
Other Notes:
Maybe we could add an example showing how to use
filterMap
to apply functions with typea -> Maybe a
to the result of a parser "for free"