TL;DR:
{-# OPTIONS_GHC -fplugin=Imp #-}
main = print $ Data.Tuple.swap ("world", "hello")
-- ("hello","world")
TL;DR:
{-# OPTIONS_GHC -fplugin=Imp #-}
main = print $ Data.Tuple.swap ("world", "hello")
-- ("hello","world")
This is so cool! I could imagine using it globally to set up a set of âpreludeâ qualified modules for all my code (containers
for instance)
Yes! Thatâs exactly how I imagine it being used. A package description might have something like this:
library
ghc-options:
-fplugin=Imp
-fplugin-opt=Imp:--alias=Data.Map.Strict:Map
-fplugin-opt=Imp:--alias=Data.Map.Lazy:LazyMap
-fplugin-opt=Imp:--alias=Data.Sequence:Seq
-fplugin-opt=Imp:--alias=Data.Set:Set
-- ...
One thing Iâd like to add to Imp is a convenient way to set up common aliases without having to list them all out manually like that.
Thank you, thank you, thank you!! This is a huge leap forward to fixing the Prelude
problem. Itâs also a great first step for beginners into the world of GHC plugins.
If I might suggest adding the config you mentioned above to the README, I think that would make it even easier to get started using this plugin effectively!
Wonderful! Potential game changer!
It will be good to document the current module to package mappings, and how to adjust those, and how/requirements to use this with scripts.
stack script
does some of this - perhaps there is overlap.
It would be great to make the module to package mappings deterministic and repeatable, as with stack. I guess this one will look for any version of the required package, thatâs already installed.
Yeah, Imp should be able to help at least a little with custom preludes, assuming that you want things to be qualified. It doesnât help at all with unqualified things. Maybe itâs because Iâve spent too much time with Elm, but that doesnât bother me too much.
I opened a pull request for adding the recommended usage to the README:
Iâm not totally sure what you mean here. Imp doesnât do any mapping between packages and modules. It just looks for qualified identifiers, gets the module names from them, and imports them if theyâre missing. You still have to specify dependencies on packages in your *.cabal
(or package.yaml
) file.
stack script
is a little different in that it will try to automatically determine package dependencies based on your import
declarations. I donât actually know if that works nicely with Imp. I havenât used Stack in a while. Can some Stack users try it out and let me know how it goes?
Sorry for asking lazily without trying, but can the aliases themselves also have multiple components, like
-fplugin-opt=Imp:--alias=Foo.Bar.Baz.Quux:Lol.Quux
?
Yes, thatâs fine. The only limitation is that both the source and target have to be valid module names. You can even clobber names if you really want to confuse people: -fplugin-opt=Imp:--alias=Data.HashMap.Strict:Data.Map
.
I guess I donât understand it yet. I am wondering eg if I use Data.Tuple.swap
in code, and that module and symbol exists in multiple packages on hackage, perhaps both installed on my machine, how would it disambiguate.
Itâs the same as if you said import Data.Tuple
instead. Something else is responsible for determining which packages are in scope, most often a package description (*.cabal
or package.yaml
file).
In a module you could use the PackageImports
extension to disambiguate, like import "base" Data.Tuple
. But Imp doesnât (yet?) support that.
Imp is quite literally only inserting import
declarations for you. If you enable Imp and used Data.Tuple.swap
somewhere, itâs exactly the same as if you said import qualified Data.Tuple
before that use of Data.Tuple.swap
.
Is it correct to put it another way: Imp automatically imports all the modules that your package knows about, qualified (and implicitly disables any unused import warnings for modules that are only imported implicitly)?
Thatâs a great clarifying question!
Thereâs another plugin called qualified-imports-plugin that works that way. It automatically imports modules for you, regardless of whether theyâre used or not.
Imp does not work that way. It will only add imports for things that are actually used in the module. Although the available packages and modules may technically be available to Imp, it doesnât make use of that information. Instead it looks for qualified identifiers that donât have a corresponding import
declaration and then adds import
s for them.
Both qualified-imports-plugin and Imp mark the imports as âimplicitâ, which prevents GHC from warning that theyâre unused. However I believe that the qualified-imports-plugin approach will prevent GHC from warning you when the entire package is unused (via -Wunused-packages
) since modules are actually imported.
What happens if an âauto-importâ forms a cycle of imports?
I ran into some surprises while answering this question! I was originally going to say that a cycle would be the same whether it happened with explicit imports or with Imp. But it turns out that you canât actually use Imp to import modules from the same unit. Thatâs surprising!
On the one hand, that means you simply canât create a cycle with Imp. On the other hand, it means Imp is slightly less useful since you canât use it to import other modules from the same unit.
I never ran into this problem when testing because I was always importing modules from other packages, like Data.Set.fromList
. I created an issue to see if thereâs a way to work around this problem:
My concern was more âboringâ - a user of Imp subsequently being confronted with a error message about a large SCC of modules formed by the extra imports Imp added:
thatâs quite clever! Thank you for releasing this.
Seconding the thanks. Itâs really useful to have this as a plugin because thatâs a much shorter path to getting the feature in the hands of users than going through a GHC proposal.