[ghc-steering-committee] #216: Qualified Do again, recommendation: accept the alternative

Iavor Diatchki iavor.diatchki at gmail.com
Fri Apr 10 15:28:02 UTC 2020


Hello,

My thoughts on this are on the git-hub thread, as I've been involved in the
discussion for quite a while.

I am in alignment with Joachim, that we should accept the module-based
variant of the proposal.

I don't have strong feelings on if the implicit names used by the
transformation should be in scope or just accessible via an import.
However, I think he makes a convincing argument that it would be pretty
weird to require names to be in scope that are not visible anywhere in the
source code, so following the choice we already made for ordinary `do` does
make sense to me.

-Iavor
PS:  Arnaud, not that it matters very much, but RankNTypes are not part of
Haskell 2010.





On Fri, Apr 10, 2020 at 6:51 AM Richard Eisenberg <rae at richarde.dev> wrote:

> Despite being the one to articulate "fully settled" and how to make
> builders with it, I now favor the module-based approach. Thanks, Joachim,
> for writing out pros and cons. I agree with the pros and con you listed
> with the module-based approach. Let's also look at some pros of the
> record-based approach:
>
> ➕ A single entity one can import, reexport, even rebind
> ➕ A single entity that can carry the documentation
> ➕ One module can export multiple builders
>
>
> With either of two module-system-improvement proposals (
> https://github.com/ghc-proposals/ghc-proposals/pull/283 or
> https://github.com/ghc-proposals/ghc-proposals/pull/295), these pros
> carry over to the module-based approach.
>
> The reason I switched camps, from favoring record-based to favoring
> module-based, is this argument, by John Ericson:
> https://github.com/ghc-proposals/ghc-proposals/pull/216#issuecomment-606109628
> Here, John is reacting to my complaint that the module-based solution will,
> to be ergonomic, require either #283 or #295. But John points out that we
> don't need to wait for #283 or #295: we can implement the module-based
> system right away. It will be usable (but sometimes clunky) right away. It
> will satisfy the problems in the motivation right away. All #283/#295 would
> do is make it less clunky.
>
> Put another way: let's imagine a Haskell with either of #283 or #295
> implemented. Then, I think, the module-based approach would be a very clear
> win, over a record-based approach with its one-off "fully settled" and
> strange restrictions on types. (The builder must have *some* record type,
> but any record type would do. There's nothing else like that anywhere.) So
> by choosing the record-based approach, we're cutting off access to the
> right design in the limit. Of course, #283/#295 are large proposals, still
> technically under discussion (but very quiet), and either one has a sizable
> implementation burden. I would never want to accept this current proposal
> in a way that would depend on #283/#295. But, as argued above, the
> module-based approach does not depend on these large proposals.
>
> My thoughts on the finer points:
>
> - I think the selectors should be in scope. It's simpler and less
> ambiguous this way, given the fact that one module can alias several
> modules to, say, M. I don't feel strongly on this point, though, and I see
> the arguments in the other direction.
> - I think this extension would be considerably more ergonomic if the new
> operators were not named (>>=), etc., but instead something like
> qualifiedBind, qualifiedThen, etc. This means that defining modules needn't
> be delicate around importing the Prelude, and importing modules don't need
> to worry about record selectors causing name clashes, etc., if they are not
> using this new extension.
>
> As we decide on this proposal, I would also like us to think about how
> this scales to other applications of rebindable syntax. For example, maybe
> we want M.if or M.[ x, y, z ] someday. I think the design *does* scale in
> such a way, which perhaps paves the way to deprecating -XRebindableSyntax.
>
> Richard
>
> On Apr 9, 2020, at 6:16 PM, Joachim Breitner <mail at joachim-breitner.de>
> wrote:
>
> Dear Committe,
>
> Proposal:
>
> https://github.com/tweag/ghc-proposals/blob/local-do/proposals/0000-local-do.rst
> Discussion (long, sorry):
> https://github.com/ghc-proposals/ghc-proposals/pull/216
>
>
> Summary:
>
> Over a year ago (on my birthday then) Arnaud created  a “local do”
> proposal that would be a more targetted variant of RebindableSyntax,
> just for “do”. In June, we sent it back because a simple syntactic
> desugaring to records didn’t quite seem right (bad type inference).
>
> In March, the authors can back with an alternative, which was using a
> Module name instead of a value of record type to indicate that monadic
> operations to use. This nicely solved the type system issues and meant
> that the translation can happen (in principle) in the parser or renamer
> stage. But some of us noticed that a builder record is nicer after all,
> and we can fix the type system issues, mostly by introducing a new concept
> of “fully settled type”; with analogies to TH stage restrictions.
>
> The authors updated the proposal accordingly, but also list the
> alternatives
> in the documents.
>
> Based on the GitHub thread we have varying opinions among the committee.
> Nevertheless, I think the authors have done a great and patient job so
> far, so
> we owe them a hopefully conclusive discussion.
>
> The main question we have to decide is:
>
>    record-based   or    module based
>
>
> Record based:
> ➕ A single entity one can import, reexport, even rebind
> ➕ A single entity that can carry the documentation
> ➕ One module can export multiple builders
> ➕ Looking forward, the builder could be dynamically constructed
>   (i.e. a local value)
> ➕ Concept of fully settled may be useful elsewhere in the future
>   and can be expanded
> ➖ Needs a new concept of “fully settled” that we don’t have elsewhere
> ➖ Initially, “fully settled” introduces staging restrictions;
>   builder values may not be usable everywhere where they are in scope.
> ➖ Lots of fluff on the defining side
>   (define a likely one-off record + a value)
> ➖ May require extensions (e.g. RankNTypes, ImpredicativeTypes)
>   on the defining side, even for a builder for the “normal” Monad
>   (see
> https://github.com/ghc-proposals/ghc-proposals/pull/216#issuecomment-600746723
>   for an example for the previous two points)
> ➕ Some compositionality (functions modifying builders), but
> ➖ not as universal as one would hope, as there is not a single builder type
>   (different qualified monads likely use different record type)
> ➕ Can support “passing arguments to do” via `(monadBuilder @Maybe).do`
>   or `(b cfg).do`
>   (once the notion of “fully settled” is powerful enough)
>
> Module based:
> ➕ Simpler to specify and understand:
>   Only affects parsing, possibly renaming. No interactions with the type
> system.
> ➕ Works out of the box with, say, `Prelude.` as the qualifier
> ➕ Benefits from future improvements to the module system
> ➖ Would need separate syntax for “passing arguments to do”, should we want
> that
> ➕ But if we had that, it can implement the record-based approach, by
> passing a
>   recoord to a suitable qualified do monad, as Iavor observes:
>
> https://github.com/ghc-proposals/ghc-proposals/pull/216#issuecomment-598859245
>
> The module-based approach would additionally raises the question whether
> * the desugaring to M.(>>) means (>>) as provided by (some) M”,
>   akin to how plain do notation works.
> * the desugaring to M.(>>) means just that (and requires (>>) to be
> imported as well),
>   akin to how RebindableSyntax works
>
>
> There was also a brief discussion of whether this should extend the set
> of operations involved to a `last` function that is used in the
> translation rule for a single-statement do notation, but it did not
> catch on.
>
>
> Recommendation:
>
> While both approaches are reasonable and have their merits, I recommend
> to accept the Module based approach. It supports most use-cases
> presented so far, in particular the Linear.do as envisioned by the
> authors, so it seems good enough™.
> Furthermore, it certainly is significantly simpler, given that it can
> be specified purely in terms of naming things, so we have a higher
> chance that this will work well with other existing and future language
> features.
>
> Should the committee follow that decision, I recommend to pick the
> variant where the value does not need to be in scope, so that its
> mechanism is close to the normal do notation, and that you can write
>
> import Linear (runLinear, other, stuff)
>>   Linear.do { … }
>
> without mucking with qualified imports or shadowing (>>). It seems odd
> to require the user to add ((>>), (>>=), fail) to an import list when
> you don’t actually mention that name anywhere.
>
>
>
>
> Cheers,
> Joachim
>
>
> --
> Joachim Breitner
>  mail at joachim-breitner.de
>  http://www.joachim-breitner.de/
>
>
> _______________________________________________
> ghc-steering-committee mailing list
> ghc-steering-committee at haskell.org
> https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
>
>
> _______________________________________________
> ghc-steering-committee mailing list
> ghc-steering-committee at haskell.org
> https://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-steering-committee
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-steering-committee/attachments/20200410/171538b1/attachment-0001.html>


More information about the ghc-steering-committee mailing list