Sugar for importing some things unqualified and the rest qualified

The “import some things unqualified and the rest qualified as Something” is very common.

A few examples are

import Data.Text (Text)
import qualified Data.Text as T
import Data.Set (Set)
import qualified Data.Set as S
import Data.Map (Map)
import qualified Data.Map as M
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as NE

So here’s a quality-of-life kind of idea:

import qualified Data.Text as T with (Text)
import qualified Data.Set as S with (Set)
import qualified Data.Map as M with (Map)
import qualified Data.List.NonEmpty as NE with (NonEmpty)

Maybe that’s better, I don’t know. It was just a lightning thought.
If anyone’s keen on it feel free to open a proposal.

6 Likes

Interesting approach. In one of my own secret lambda calculus, I added a Python-like using statement that automatically imports qualified, but also imports any data types who’s names start with the module’s last name. Eg:

using Data.Text
-- ^ is the same as
import Data.Text (Text, TextOptions, ...)
import qualified Data.Text as Text

I also had an experiment to allow the as keyword for renaming imported functions / constructs too, and not just modules, eg:

import Data.ByteString (ByteString, foo as fooByteString)
import Data.Text hiding (fooText as foo) -- It also works for hiding!

The idea for that is that it also helps reduce churn.

Eh I find this particular syntax confusing. with makes it seem like it’s adding these imports in the qualified namespace. I think what might work is something like

import Data.Text
  with (Text)
  with qualified as T

Personally, a bigger wishlist item is to force an explicit import list, which may be import Foo (..), which imports everything (borrowing syntax of importing all fields in a type). I’m not terribly bothered by repeating imports like you mentioned, especially with ImportQualifiedPost.

Just drop the qualified keyword

import Data.Text as T
import Data.Set as S
import Data.Map as M
import Data.List.NonEmpty as NE

This way you get all names both qualified and unqualified. Use an unqualified name if it’s unambiguous across all imported modules. Use a qualified name to resolve ambiguities, if any.

Already supported by Haskell. Always has been!

9 Likes

Indeed, well thought of :stuck_out_tongue:

Related to this, don’t forget that we have ImportQualifiedPost

import Data.Map (Map)
import Data.Map qualified as Map

and then no more ugly qualified getting itself in front of your module names!

5 Likes

I do wish libraries could insist “I am meant to be imported qualified as such” with unqualified being an exceptional option.

(Can’t believe i’m saying this) like Golang.

2 Likes

There has already been the exact same proposal a few year ago. It was rejected I think because nobody could agree on the syntax and left a bitter taste to people involved on it. I have to admit that none of the syntax felt right though.

However it is still a genuine issue which will be nice to resolve.

1 Like

The problem is you now have to qualify things from the Prelude that you didn’t have to.

3 Likes

You can also use ; and put them on the same line

import Data.Map (Map); import Data.Map qualified as Map

I’d suggest exposing rather than with, but otherwise I like this a lot.

I had a quick look at the ghc-proposals repos and couldn’t find this, do you happen to remember something that would be a good search term?

I like exposing from elm

import qualified Data.Text as T exposing(Text)

In fact, as it’s a new syntax we even don’t have to follow the previous one so

import Data.Text exposing(Text) as T

could suffice. theres is no need for qualified and exposing and as

or even just

import Data.Text(Text) as T

2 Likes

I can’t find the proposal neither but I remember it being quite a stir on reddit at the time.
But here is the a in depth conversation on a ghc issue created by @acowley.
The ticket also refers to the reddit conversation and a few proposals:

1 Like

The latest proposal which allows this is the Local modules porposal by Richard Eisenberg.

It says it is an alternative to the Structured imports proposal, which may be what you’re talking about.

I was refering to the “Haskell-cafe” proposal, 8 years ago, which indeed didn’t make it to a formal proposal (which I’m not sure existed at the time).

That’s not much of a problem. You’re probably thinking of list functions, what I do is this

import Data.List as L
1 Like

I understand that it is what you are doing, but it is a problem for me (at least).
If I use the implicit Prelude, which include Data.List, I don’t want to have to import Data.List explicitely.

Or just put up with writing imports over two lines? Is it really worth introducing new syntax for this? Any code you write using that syntax will be incompatible with all previous compiler versions

https://osa1.net/posts/2020-01-22-no-small-syntax-extensions.html

2 Likes

That’s a fair point, but that didn’t the introduction of the ImportQualifiedPost extension.
Also, people would still have the choice to use the extension or not.

Prelude, and all the local definitions.

1 Like