Before I start, I must set two words and ideas straight. An entity refers to a value definition, a data constructor, a field name, a type constructor, a type synonym, a class, or a class method; so, things that can be exported and imported by names. Now, my point here is that the same entity can have several long names due to re-exports. Here is how it happens:
module Origin where species = "species" |
module ReExport(species) where import Origin |
module Main(main) where import Origin import ReExport main = mapM_ putStrLn [Origin.species, ReExport.species, species] |
This set of modules is valid. Inside Main, 3 different names (2 long, 1 short) refer to the same entity: “Origin.species”, “ReExport.species”, “species”. Especially, “species” here is not ambiguous. One way to think of this: if you follow the import-export chains, both “Origin.species” and “ReExport.species” trace back to the same site of declaration or definition (module Origin, line 2), and this is how we know they refer to the same entity, and therefore “species” unambiguously refers to that entity too. An ambiguity would require two different underlying entities.
You probably know you can assign an “as” name when importing:
module LeftModule where vl = "vl" |
module RightModule where vr = "vr" |
module Main(main) where import LeftModule as L import RightModule as R main = mapM_ putStrLn [L.vl, R.vr] |
To recap: with importing “as”, you get the names “L.vl” and “vl” referring to one entity, and the names “R.vr” and “vr” referring to another entity. (I use the long names in Main because they show interesting effects later.) It is also important to note that you don't get the names “LeftModule.vl” or “RightModule.vr”.
The surprising and convenient variation is that different import lines can be given the same “as” name:
module LeftModule where vl = "vl" |
module RightModule where vr = "vr" |
module Main(main) where import LeftModule as M import RightModule as M main = mapM_ putStrLn [M.vl, M.vr] |
You can use this for evil or good. If you assign the same name to conceptually unrelated modules, that is of course confusing. But you can assign the same name to conceptually related modules, and that is a convenience for you. Of course, this is all subjective and context-dependent: the module authors may think that the modules are conceptually unrelated, but from your perspective, for your particular application, they may be related enough. Go with your heart, you have good enough taste to decide for yourself.
The surprise, though, hasn't finished:
module LeftModule where vl = "vl" |
module RightModule where vr = "vr" |
module Main(main) where import LeftModule import RightModule as LeftModule main = mapM_ putStrLn [LeftModule.vl, LeftModule.vr] |
Apparently, the Haskell Report does not forbid this, and empiricially both GHC and Hugs support it.
When you decide to give a common “as” name to a range of modules, sometimes you face the dilemma that they contain some name clashes:
module LeftModule where vl = "vl" c = "Left c" |
module RightModule where vr = "vr" c = "Right c" |
module Main(main) where import LeftModule as M import RightModule as M main = putStrLn M.c -- error, ambiguous, and we cannot say LeftModule.c or RightModule.c |
Before we look at a solution (easy), let us first marvel at the error messages:
ERROR "f.hs":4 - Ambiguous qualified variable occurrence "M.c" *** Could refer to: RightModule.c LeftModule.c
Ambiguous occurrence `M.c' It could refer to either `M.c', imported from `LeftModule' at f.hs:2:3-24 (and originally defined at LeftModule.hs:3:3) or `M.c', imported from `RightModule' at f.hs:3:3-25 (and originally defined at RightModule.hs:3:3)
OK, so an easy solution uses the fact that we can import the same module as many times as we want, under as many different names as we want, customizing the import lists as much as we want:
module LeftModule where vl = "vl" c = "Left c" |
module RightModule where vr = "vr" c = "Right c" |
module Main(main) where import LeftModule as M import LeftModule as L(c) import RightModule as M import RightModule as R(c) main = mapM_ putStrLn [L.c, R.c, M.vl, M.vr] |
Before I continue, I must recap the effects of import
qualified
. To be completely clear, I use this example
module:
module Origin where species = "species" |
and I draw this table of exactly which names are introduced (they all
refer to the same entity) by import Origin
, import Origin
as Q
, import qualified Origin
, or import qualified
Origin as Q
, respectively:
(no as ) |
as Q |
|
---|---|---|
(no qualified ) |
Origin.species, species | Q.species, species |
qualified |
Origin.species | Q.species |
The most important point: qualified
does not introduce
short names. The second most important point: long names are determined by
as
when present.
The rules for export lists are pretty simple. For now, ignore
module
items (they are covered later). One rule: if you use
long names, use the same long names as you would use in the module body.
Example:
module Origin where species = "species" genus = "genus" |
module Exporter(species, Q.genus, rail, Exporter.ship) where import Origin as Q rail = "rail" ship = "ship" |
module Main(main) where import Exporter main = mapM_ putStrLn [species, genus, rail, ship] |
Notice how Exporter's export list uses Q.genus and Exporter.ship, which are valid long names in Exporter's body. Conversely, Origin.genus is invalid in both Exporter's body and export list.
Another rule: even though you can use long names for disambiguation in the module body, it will not help in the export list. Here is an example:
module Origin where clash = "Origin clash" -- entity #1 |
module Exporter(Origin.clash, Exporter.clash) -- error: ambiguous where import Origin clash = "Exporter clash" -- entity #2 |
To understand why it is considered ambiguous and therefore the Haskell designers decided to forbid it, do not think of what Exporter sees; think of what you would see if you were allowed to import it:
module Main(main) where import Exporter main = print Exporter.clash -- eh? entity #1? entity #2? |
In other words, unfortunately for an importer, there would be two entities both called Exporter.clash, and it is not like one of them could be called Exporter.Origin.clash.
There are other rules, but they are more well-known or less surprising, and this “fine print” article will not cover them.
Now we get to the rule about module
items, i.e., things
like module Exporter(module Origin)
. As it turns out, their
actual semantics look tricky if you think that module
literally
means module, but are straightforward once you are liberated from that
intuition. Here is the straightforward, real meaning:
module Exporter(… module Q …)
means: for each entity,
if there exists a short name e such that the entity has both names Q.e and
e inside Exporter, then export that entity. (It is alright for the short
name e to be ambiguous in the body of Exporter, as long as the rest of the
export list does not try to export the other e.)
The first awakening is that this is totally about qualifiers (especially “as” names) and almost nothing about modules afterall. Example of failing to understand:
module Exporter(module Origin) -- error, it is called Q here where import Origin as Q |
Example of succeeding to understand:
module LeftModule where vl = "vl" -- entity #1 solo = "solo" -- entity #nada |
module RightModule where vr = "vr" -- entity #2 |
module Exporter(module Q) -- exports #1, #2 where import LeftModule -- line (A) import LeftModule as Q(vl) -- line (B) import RightModule as Q -- line (C) -- the following definition does not hurt the export list vl = "Exporter private vl" -- line (D), entity #dead |
Detailed analysis:
entity | has Q.e long name | has short name | exported |
---|---|---|---|
#1 | ✓ Q.vl (B) | ✓ vl (A,B) | ✓ |
#2 | ✓ Q.vr (C) | ✓ vr (C) | ✓ |
#nada | ✕ | ✓ solo (A) | ✕ |
#dead | ✕ | ✓ vl (D) | ✕ |
Other long names such as LeftModule.solo or Exporter.vl do not matter.
Although entity #dead has short name vl just like #1, it does not hurt
the export list, unless you try to do (module Q, Exporter.vl)
or (module Q, module Exporter)
.
The second interesting effect is that importing with qualified
may prevent some entities from being exported, since it does not introduce
certain short names, and a module
item skips those entities
without short names. This is why the previous section
Import Qualified is important. Example:
module Origin where species = "species" -- entity #1 genus = "genus" -- entity #2 |
module Exporter(module Q) -- exports #1 where import Origin as Q(species) -- line (A) import qualified Origin as Q -- line (B) import qualified Origin -- line (C) |
Detailed analysis:
entity | has Q.e long name | has short name | exported |
---|---|---|---|
#1 | ✓ Q.species (A,B) | ✓ species (A) | ✓ |
#2 | ✓ Q.genus (B) | ✕ | ✕ |
The other long names (Origin.species, Origin.genus) do not matter.
The most funny effect is that only the simultaneous presence of long and short names matters; it does not matter how we got them. The two names can be obtained from different import lines, in fact from quite different import-export chains. The line that gives the short name does not have to use the same qualifier as the line that gives the long name.
module Origin where species = "species" -- entity #1 | |
module LeftModule(species) where import Origin |
module RightModule(species) where import Origin |
module Exporter(module LeftModule) -- exports #1 where import qualified LeftModule -- line (A) import RightModule -- line (B) |
Detailed analysis:
entity | has LeftModule.e long name | has short name | exported |
---|---|---|---|
#1 | ✓ LeftModule.species (A) | ✓ species (B) | ✓ |
It does not matter that line (B) has nothing to do with LeftModule.
With that, I close with a puzzle for you! The code:
module Puzzle(module Q) where import qualified Data.Maybe as Q |
The question: what does Puzzle export, and why are they exported despite
the qualified
?
I have more Haskell Notes and Examples