<div dir="ltr"><div>This seems like it could be thought of as a special case of record selection. (apologies if this has been discussed before, I haven't read the whole discussion thread.)</div><div><br></div><div>The syntax is even reminiscent of record selection. But unlike selecting a single field, we're selecting a bunch of fields and using them to desugar a do expression.This makes me wonder: would it be possible to handle the typing by generating HasField constraints for (>>=) and friends? And would that avoid needing to talk about "fully settled" types?</div><div><br></div><div>Cheers</div><div>Simon<br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, 9 Apr 2020 at 18:17, Joachim Breitner <<a href="mailto:mail@joachim-breitner.de">mail@joachim-breitner.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Dear Committe,<br>
<br>
Proposal: <br>
<a href="https://github.com/tweag/ghc-proposals/blob/local-do/proposals/0000-local-do.rst" rel="noreferrer" target="_blank">https://github.com/tweag/ghc-proposals/blob/local-do/proposals/0000-local-do.rst</a><br>
Discussion (long, sorry):<br>
<a href="https://github.com/ghc-proposals/ghc-proposals/pull/216" rel="noreferrer" target="_blank">https://github.com/ghc-proposals/ghc-proposals/pull/216</a><br>
<br>
<br>
Summary:<br>
<br>
Over a year ago (on my birthday then) Arnaud created a “local do”<br>
proposal that would be a more targetted variant of RebindableSyntax,<br>
just for “do”. In June, we sent it back because a simple syntactic<br>
desugaring to records didn’t quite seem right (bad type inference).<br>
<br>
In March, the authors can back with an alternative, which was using a<br>
Module name instead of a value of record type to indicate that monadic<br>
operations to use. This nicely solved the type system issues and meant<br>
that the translation can happen (in principle) in the parser or renamer<br>
stage. But some of us noticed that a builder record is nicer after all,<br>
and we can fix the type system issues, mostly by introducing a new concept<br>
of “fully settled type”; with analogies to TH stage restrictions.<br>
<br>
The authors updated the proposal accordingly, but also list the alternatives<br>
in the documents.<br>
<br>
Based on the GitHub thread we have varying opinions among the committee.<br>
Nevertheless, I think the authors have done a great and patient job so far, so<br>
we owe them a hopefully conclusive discussion.<br>
<br>
The main question we have to decide is:<br>
<br>
record-based or module based<br>
<br>
<br>
Record based:<br>
➕ A single entity one can import, reexport, even rebind<br>
➕ A single entity that can carry the documentation<br>
➕ One module can export multiple builders<br>
➕ Looking forward, the builder could be dynamically constructed<br>
(i.e. a local value)<br>
➕ Concept of fully settled may be useful elsewhere in the future<br>
and can be expanded<br>
➖ Needs a new concept of “fully settled” that we don’t have elsewhere<br>
➖ Initially, “fully settled” introduces staging restrictions;<br>
builder values may not be usable everywhere where they are in scope.<br>
➖ Lots of fluff on the defining side<br>
(define a likely one-off record + a value)<br>
➖ May require extensions (e.g. RankNTypes, ImpredicativeTypes)<br>
on the defining side, even for a builder for the “normal” Monad<br>
(see <a href="https://github.com/ghc-proposals/ghc-proposals/pull/216#issuecomment-600746723" rel="noreferrer" target="_blank">https://github.com/ghc-proposals/ghc-proposals/pull/216#issuecomment-600746723</a><br>
for an example for the previous two points)<br>
➕ Some compositionality (functions modifying builders), but<br>
➖ not as universal as one would hope, as there is not a single builder type<br>
(different qualified monads likely use different record type)<br>
➕ Can support “passing arguments to do” via `(monadBuilder @Maybe).do`<br>
or `(b cfg).do`<br>
(once the notion of “fully settled” is powerful enough)<br>
<br>
Module based:<br>
➕ Simpler to specify and understand:<br>
Only affects parsing, possibly renaming. No interactions with the type system.<br>
➕ Works out of the box with, say, `Prelude.` as the qualifier<br>
➕ Benefits from future improvements to the module system<br>
➖ Would need separate syntax for “passing arguments to do”, should we want that<br>
➕ But if we had that, it can implement the record-based approach, by passing a<br>
recoord to a suitable qualified do monad, as Iavor observes:<br>
<a href="https://github.com/ghc-proposals/ghc-proposals/pull/216#issuecomment-598859245" rel="noreferrer" target="_blank">https://github.com/ghc-proposals/ghc-proposals/pull/216#issuecomment-598859245</a><br>
<br>
The module-based approach would additionally raises the question whether<br>
* the desugaring to M.(>>) means (>>) as provided by (some) M”,<br>
akin to how plain do notation works.<br>
* the desugaring to M.(>>) means just that (and requires (>>) to be imported as well),<br>
akin to how RebindableSyntax works<br>
<br>
<br>
There was also a brief discussion of whether this should extend the set<br>
of operations involved to a `last` function that is used in the<br>
translation rule for a single-statement do notation, but it did not<br>
catch on.<br>
<br>
<br>
Recommendation:<br>
<br>
While both approaches are reasonable and have their merits, I recommend<br>
to accept the Module based approach. It supports most use-cases<br>
presented so far, in particular the Linear.do as envisioned by the<br>
authors, so it seems good enough™.<br>
Furthermore, it certainly is significantly simpler, given that it can<br>
be specified purely in terms of naming things, so we have a higher<br>
chance that this will work well with other existing and future language<br>
features.<br>
<br>
Should the committee follow that decision, I recommend to pick the<br>
variant where the value does not need to be in scope, so that its<br>
mechanism is close to the normal do notation, and that you can write<br>
<br>
import Linear (runLinear, other, stuff)<br>
…<br>
Linear.do { … }<br>
<br>
without mucking with qualified imports or shadowing (>>). It seems odd<br>
to require the user to add ((>>), (>>=), fail) to an import list when<br>
you don’t actually mention that name anywhere.<br>
<br>
<br>
<br>
<br>
Cheers,<br>
Joachim<br>
<br>
<br>
-- <br>
Joachim Breitner<br>
<a href="mailto:mail@joachim-breitner.de" target="_blank">mail@joachim-breitner.de</a><br>
<a href="http://www.joachim-breitner.de/" rel="noreferrer" target="_blank">http://www.joachim-breitner.de/</a><br>
<br>
<br>
_______________________________________________<br>
ghc-steering-committee mailing list<br>
<a href="mailto:ghc-steering-committee@haskell.org" target="_blank">ghc-steering-committee@haskell.org</a><br>
<a href="https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee" rel="noreferrer" target="_blank">https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee</a><br>
</blockquote></div>