Plain source file: base/Modules/ModSysAST.lhs (2002-08-20)

ModSysAST is imported by: AST4ModSys, CheckModules, Modules, WorkModule.

> module ModSysAST where
> import NamesEntities
> import Relations

Abstract Syntax


As described in the Haskell 98 report \cite[Section 5.1]{Haskell98}, a Haskell module consists of a name, an export specification, a number of import declarations and a number of local definitions. We use the following data structure to represent modules:

> data Module = Module {
>   modName     :: ModName,
>   modExpList  :: Maybe [ExpListEntry],
>   modImports  :: [Import],
>   modDefines  :: Rel Name Entity }

The concrete syntax of Haskell allows an abbreviated form, where the module name and the export specification are omitted. This is an abbreviation for a module with name ``Main'' and an export specification exporting a single entity named ``main'' \cite[Section 5.1]{Haskell98} and will in our abstract syntax be represented in its expanded form.

An element of the export specification is either an entity name or a module name as described by the data structure ExpListEntry. For entities with subordinate names, a programmer may also provide a subordinate export list. This list is modeled by the data structure SubSpec. It specifies which of the subordinate entities currently in scope are to be exported.

> data ExpListEntry = EntExp (EntSpec QName)
>                   | ModuleExp ModName
> data EntSpec j    = Ent j (Maybe SubSpec)
> data SubSpec      = AllSubs | Subs [Name]

\begin{ex} For the Haskell module:

  module A (f,C(..),module M) where ...

the field modExpList would be:

 Just [EntExp (Ent "f" Nothing),
       EntExp (Ent "C" (Just AllSubs)),
       ModuleExp "M"]


The structure EntSpec is used in both import and export lists. Because qualified names are allowed in export lists, but not in import lists, we use the parameter j to capture the different types of EntSpec.

At first it may seem that we may eliminate AllSubs by thinking of it as just an abbreviation for all the methods/value constructors of its owner. This however is not the case, as its meaning depends on what entities are currently in scope, and this is one of the things the module system computes.

The lack of an export list is a special form of export specification: one saying that only---and all---locally defined entities are to be exported \cite[Section 5.2]{Haskell98}. It is not an abbreviation for the empty export list, or the export list containing only module M (where M is the current module). We represent this explicitly by using the Maybe type constructor in the modExpList field.

To make use of entities defined in other modules, programmers have to supply import declarations. Their purpose it to specify what entities are to be imported, which module provides the required entities, and valid ways to refer to the imported entities.

> data Import = Import {
>   impQualified  :: Bool,
>   impSource     :: ModName,
>   impAs         :: ModName,
>   impHiding     :: Bool,
>   impList       :: [EntSpec Name] }

The impSource field is the only field that must be specified explicitly in an import specification. It specifies the name of the module from which entities will be imported. All remaining fields take on a default value, if not specified explicitly.

There are two flavors of import declarations: the ones specifying what names are to be imported, and the ones specifying what names are not to be imported (sometimes called ``hiding'' imports). The boolean field impHiding distinguishes between those two.

The field impList contains the actual specification, which has structure similar to the export list of a module. There are two differences: there are no ``module'' imports, and all names in the list must be simple. To capture this similarity we reuse the EntSpec data type. If this field is omitted the specification is assumed to be [], and the impHiding field is set to True. This has the effect of importing all exported entities of the source module.

Sometimes it is more convenient to qualify names imported from a module not using the module name, but some other alias instead. This is particularly useful if the name of the source module is quite long and a programmer needs to refer often to imported entities by their qualified names. The field impAs stores this alias. If the alias is omitted, this field is assumed to have the same value as the impFrom fields (i.e. we use the module name in qualified names).

Finally in some situations it might be preferable to only import entities with their qualified names. This can be done with the so called qualified imports. The field impQualified distinguishes qualified from normal imports.

\begin{ex} The import:

 import Prelude as P hiding (and,Bool(True))

is represented by the data structure:

 Import {impQualified = False,
         impSource    = "Prelude",
         impAs        = "P",
         impHiding    = True,
         impList      = [Ent "and" Nothing,
                         Ent "Bool" (Just (Subs ["True"]))]



(HTML for this module was generated on 2009-01-04. About the conversion tool.)