Implement QualifiedDo - #3373
Conversation
|
(Tests fail because |
|
I personally like this feature, as I think it makes rebindable-do actually useful. I don't know of anyone using the feature in earnest because the ergonomics are so terrible, so at best I consider rebindable-do a neutral side-effect of not having a hard dependency on Prelude. But I know the reception in the ticket was mixed. I think we should make a decision either way if this is something that we want to merge (now or eventually) rather than letting this continue to bit-rot. |
|
@natefaubion: Yes, I agree. I'm a little hesitant for the same reasons I gave in #3245, but I'll admit that I don't remember finding myself in a position where I was wanting to use rebindable syntax like this, and in fact I always did view rebindable syntax as a neutral consequence of separating Prelude from the compiler, rather than a feature that I expected to get much use. But looking back at the ticket, I think the ergonomics argument makes sense. You and @garyb being in favour is sufficient for me to say sure, let's do it. @pkamenarsky this is perhaps a bit late now, but you can trigger a new CI build by pushing an empty commit, or by rebasing your PR on master. |
|
Additionally, if we are doing this, I think we should support |
1a8e990 to
8678845
Compare
|
|
|
Ok, I think this might be ready for review 🎉 |
|
I’d love to use this in this react-basic branch! I’ve tried a few different approaches to scoping bind and it’s all pretty gross. It’s also harder to understand (both learning and debugging) than qualified do 🙂 In this example I had to move the inner do block out so they each have their own bind scope: https://github.com/spicydonuts/purescript-react-basic/blob/hooks/examples/counter/src/Counter.purs And in this one the “convenience” args I was trying we’re kind of useless for the helper function: |
|
I think the approach is straightforward. The only outstanding question I have is how this interacts with something like docs/pursuit. I know |
|
This should be fine, I think, since a) the |
|
Well I mean there are changes in the desugaring too, but |
|
I gave this branch a try and it works! Counter, ControlledInput One thing I noticed is that it seemed to work even without |
|
What are the next steps or blockers here? |
Can you explain what you meant by these comments? |
|
The module I defined top level |
| , parseDo | ||
| , parseAdo | ||
| , P.try parseDo | ||
| , P.try parseAdo |
There was a problem hiding this comment.
I don't think we want to add backtracking here. This will backtrack on any failure inside a do-block, which will result in poor errors. We only want to apply backtracking to the parsing of the do keyword, which means we need to move this into parseDo and parseAdo.
There was a problem hiding this comment.
Done. Interestingly, my intuition was that by using <|> the parser would try consuming the qualified keyword first and only if that fails try and parse the unqualified one:
(parseQualified (reserved "do") >>= pure ∘ getQual) <|> (reserved "do" *> pure Nothing)
However we still need to backtrack explicitly while parsing the qualified version, otherwise every qualified token is expected to be do/ado.
There was a problem hiding this comment.
<|> will only fallback to the next branch if you have wrapped in try or you have not consumed any tokens. parseQualified likely consumes the qualification, so when it does not get a do, it will not fallback to the next alternative unless you explicitly wrap it in try.
| parseDo :: TokenParser Expr | ||
| parseDo = do | ||
| m <- parseQualified (reserved "do") >>= \(Qualified m _) -> pure m | ||
| m <- P.try (parseQualified (reserved "do") >>= pure . getQual) <|> (reserved "do" *> pure Nothing) |
There was a problem hiding this comment.
>>= pure . k is just fmap.
|
@spicydonuts I cannot reproduce that issue with this branch. If I don't export |
|
I tried this here and it seems like it was probably just a build caching issue:
|
|
By "build", do you mean a full compiler build, or ide build? |
|
In any case, that doesn't sound like an issue with this PR specifically. |
|
Full, using |
|
@spicydonuts I've tried, but I still can't reproduce an error calling Does anyone have any other comments? |
|
Thank you @pkamenarsky for implementing this! Thank you @spicydonuts for trying this out. 🎉 |
* Implement QualifiedDo * Improve QualifiedDo tests * Implement QualifiedAdo * Trigger CI * Backtrack only while parsing the do/ado keywords * >>= pure . k is just fmap * Clean up tests
Implements #3245.
Now, the following is possible:
IxMonad.purs:Main.purs:instead of having to rebind
bindexplicitly.There's no change in behaviour if
dois left unqualified:If there's interest I'll add support for
adoas well.