Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do these corner cases in Haskell's import-as work and what do they do?

Tags:

import

haskell

I've come across some modules that contain particularly strange imports.

First of all, I have seen a module A that imports an other module as himself. For example:

-- module A.hs
module A where
import B as A   -- ???

f = id

What does this do? Why is the above permitted at all?

However what most troubles me is that the code is actually of this kind:

module A where
import B as A  -- Okay, assume this works...
import C as A  -- ??? A is already defined!

f = id

Why can more then one module be imported with the same name? What does this achieve? I thought that these kind of imports weren't permitted and also A Gentle Introduction to Haskell states that:

it is illegal to import two different entities having the same name into the same scope.

However these imports work fine. Yet an other strange thing that bugs me is exporting the module itself:

module A (module A) where

To summarize, given the following MWE:

-- A.hs
module A (module A) where
import B as A
import C as A

f = id

-- B.hs
module B where

g = id

-- C.hs
module C where

h = id
  1. Are the imports following the standards or is this some bug of GHC? It doesn't look like a bug, but I can't find any reference that explains all these corner cases.
  2. What's the exact result achieved? I mean: which names are imported and/or exported from A?
like image 694
Bakuriu Avatar asked May 02 '14 08:05

Bakuriu


1 Answers

Name qualifiers are not the same thing as module names. A name qualifier is just a collective scope, you can make it refer to any number of modules. Normally you won't add more than one, but in one case you almost always add plenty of modules: in the unqualified scope. import Data.List might be read as something like import qualified Data.List as "": it arranges that, say, sortBy will be found when referring to it with an "empty qualifier", i.e. with none. But we could "rename" that scope:

module Main where

import qualified Prelude as P
import qualified Data.List as P
import qualified Data.Ord as P

main :: P.IO ()
main = do    -- `do` is syntax, not a name!
   P.print  P..  P.map  P.snd  P.$  P.sortBy  (P.comparing  P.fst)
     [(4,'o'),(6,' '),(0,'H'),(1,'e'),(3,'l'),(9,'r'),(7,'W'),(10,'l'),(8,'o'),(2,'l'),(5,','),(11,'d'),(12,'!')]

The only qualifiers that are fixed are the ones specific to the module in your file itself: that's always both in unqualified scope, and in the scope automatically named after the module. And for definitions, you must use the unqualified form.

For module A (module A), that seems pretty much bogus. I don't think module exports are really well thought-through. They only work properly when you refer to an actual module, not just a name qualifier, i.e.

module PowerPrelude (module A)
import qualified Prelude as A
import qualified Data.List as A
import qualified Data.Ord as A

will not work. Which makes you wonder why it's allowed to declare such an export at all. Might indeed be a bug here.

like image 95
leftaroundabout Avatar answered Nov 08 '22 04:11

leftaroundabout