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

Simon Peyton Jones simonpj at microsoft.com
Tue Apr 14 11:36:06 UTC 2020


In GHC we have two concepts:

  *   Qualified names like M.foo, which always mean "the foo imported from module M - albeit with import-qualified you can change the local name"
  *   Original names, also typically written M.foo, meaning "the foo defined in module M"


In list comprehensions, conditionals etc, we always desugar to original names; it doesn't matter if they are in scope.  You don't even have to import the Prelude.  But GHC knows the defining module.

With this "does not have to be in scope" business, you are inventing (and requiring someone to implement) a new scheme:

  *   Quasi-original names: M.foo means "the foo exported by module M"

I'm not at all keen this new mechanism

  *   Presumably there is no opportunity to do the import-qualified thing?  Or maybe you can say "import This.That as M ()", thus importing nothing but giving a local name M?
  *   Presumably you must any other M.foo that is already in scope?

But I can see why you want this, because you don't want to list all those operations one by one.  Exactly!   You want to group them into a ... record!  You want  import Linear( linear ), and then you can say linear.do { ... }.

I'm pretty strongly against inventing quasi-original names.  The module system is surprising complex already.  I suppose you can always define an auxiliary module to do the grouping, thus
               import Linear.Monad as L    -- Exports the operators for linear-do

Simon

From: ghc-steering-committee <ghc-steering-committee-bounces at haskell.org> On Behalf Of Richard Eisenberg
Sent: 14 April 2020 09:47
To: Spiwack, Arnaud <arnaud.spiwack at tweag.io>
Cc: Simon Peyton Jones via ghc-steering-committee <ghc-steering-committee at haskell.org>; Joachim Breitner <mail at joachim-breitner.de>
Subject: Re: [ghc-steering-committee] #216: Qualified Do again, recommendation: accept the alternative

About whether names must be in scope (only):

What do module prefixes in code mean? I claim: they refer to a set of in-scope identifiers. That's it. Because of the way Haskell allows module aliasing, they do not refer to, say, a compilation unit, or some `module` structure. A module prefix identifies just a flat set of identifiers. This "set" view works nicely both with module aliasing and the way that Haskell specifies what "module M" means in an export list.

Since a module prefix refers to a set of in-scope identifiers, it seems to make sense only to have the same meaning with M.do syntax. With the "identifiers do not need to be in scope" approach, then the M in M.do is now referring, I think, to a set of `module` structures that have been aliased to M in the import list. We then have to look in the export lists of each of those modules to see what is available. And what if multiple modules in the same set have bind operators in their export lists? That would be ambiguous, I suppose. Now, what if multiple modules in the module set export disjoint subsets of the operators? (For example, we have `import M1 as M` and `import M2 as M`, where `M1` exports `(>>)` and `M2` exports `(>>=)`.) I suppose we'd combine them. My problem is that we would have to specify all of these rules with the "out of scope" interpretation. With the in-scope interpretation, all of these answers follow directly from the specification. Much simpler!

All that said, it seems the majority favor the out-of-scope interpretation. I truly don't feel strongly and am happy to go with that. I just wanted to expand my argument slightly to see if it won any of you over.

Richard


On Apr 14, 2020, at 7:58 AM, Spiwack, Arnaud <arnaud.spiwack at tweag.io<mailto:arnaud.spiwack at tweag.io>> wrote:



On Fri, Apr 10, 2020 at 10:43 AM Joachim Breitner <mail at joachim-breitner.de<mailto:mail at joachim-breitner.de>> wrote:
I am surprised this is so controversial. There are many things in
Haskell that are used that are not imported:

 * The desugaring of plain do notation (!)
 * The desugaring of if-then-else (no need to have True/False in scope)
 * The desugaring of boolean guards
   (again, no need to have True/False in scope)
 * Instances
 * And because of that, `foo.bar` according to RecordDotSyntax will
   not require `bar` to be in scope, as this is just an
   instance accessed via HasField "bar" (if I am not mistaken)

In contrast, there is nothing where you have to import some `foo` when
you don't actually mention `foo` in your source code.

Which seems a pretty reasonable rule:
Import the things you write; no more, no less!

I wanted to add, for the record, that Joachim's argument convinced me that, indeed, were we to go for the module-qualified do approach, we probably shouldn't require the names to be in scope.

However, it makes the module-qualified approach more counter-intuitive to me: it doesn't make sense to me to use the namespace `M` to refer to a term which is not in this namespace. Obviously, Joachim, you have a different intuition about this.
_______________________________________________
ghc-steering-committee mailing list
ghc-steering-committee at haskell.org<mailto: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/20200414/dea23c5c/attachment-0001.html>


More information about the ghc-steering-committee mailing list