[[project @ 2005-02-01 17:27:34 by simonpj]
simonpj**20050201172734
First cut at hs-boot documentation
] {
hunk ./ghc/docs/users_guide/separate_compilation.xml 615
+
+ How to compile mutually recursive modules
+
+ module system, recursion
+ recursion, between modules
+
+ GHC supports the compilation of mutually recursive modules.
+ This section explains how.
+
+ Every cycle in the module import graph must be broken by a hs-boot file.
+ Suppose that modules A.hs and B.hs are Haskell source files,
+ thus:
+
+module A where
+ import B( TB(..) )
+
+ newtype TA = MkTA Int
+
+ f :: TB -> TA
+ f (MkTB x) = MkTA x
+
+module B where
+ import {-# SOURCE #-} A( TA(..) )
+
+ data TB = MkTB !Int
+
+ g :: TA -> TB
+ g (MkTA x) = MkTB x
+
+hs-boot
+ filesimporting,
+ hi-boot files
+Here A imports B, but B imports
+A with a {-# SOURCE #-} pragma, which breaks the
+circular dependency. For every module A.hs that is {-# SOURCE #-}-imported
+in this way there must exist a souce file A.hs-boot. This file contains an abbreviated
+version of A.hs, thus:
+
+module A where
+ newtype TA = MkTA Int
+
+A hs-boot file is compiled by GHC, just like a hs file:
+
+ ghc -c A.hs-boot
+
+Just as compiling A.hs produces an
+interface file A.hi, and an object file
+A.o, so compiling A.hs-boot
+produces an interface file
+A.hi-boot, and an pseudo-object file
+A.o-boot. The interface file
+A.hi-boot has exactly the same format as any
+other interface file. The pseudo-object file is empty (don't link it!), but it is
+very useful when using a Makefile, to record when the A.hi-boot was
+last brought up to date.
+
+To compile these three files, issue the following commands:
+
+ ghc -c A.hs-boot -- Poduces A.hi-boot, A.o-boot
+ ghc -c B.hs -- Consumes A.hi-boot, produces B.hi, B.o
+ ghc -c A.hs -- Consumes B.hi, produces A.hi, A.o
+ ghc -o foo A.o B.o -- Linking the program
+
+
+There are several points to note here:
+
+
+ The file A.hs-boot is a programmer-written source file.
+ It must live in the same directory as its parent source file A.hs.
+ (Currently, if you use a literate source file A.lhs you must
+ also use a literate boot file, A.lhs-boot.)
+
+
+ The hi-boot generated by compiling a hs-boot
+ file is in machine-generated binary format.
+ You can display its contents with ghc --show-iface. If you
+ specify a directory for interface files, the flag, then that affects
+ hi-boot files too.b
+
+ Hs-boot files are written in a subset of Haskell. In particular, the module
+ exports and imports, and the scoping rules are exactly the same as in Haskell. Hence, to
+ mention a non-Prelude type or class, you must import it.
+
+ When a hs-boot file A.hs-boot
+ is compiled, it is checked for scope and type errors.
+ When its parent module A.hs is compiled, the two are compared, and
+ an error is reported if the two are inconsistent.
+
+
+ If hs-boot files are considered distinct from their parent source
+ files, and if a {-# SOURCE #-} import is considered to refer to the
+ hs-boot file, then the module import graph must have no cycles. The ghc -M
+ will report an error if a cycle is found.
+
+
+
+
+A hs-boot file need only contain the bare
+ minimum of information needed to get the bootstrapping process
+ started. For example, it doesn't need to contain declarations
+ for everything that module
+ A exports, only the things required by the
+ module that imports A recursively.
+A hs-boot file is written in a subset of Haskell:
+
+ The module header, and import statements, are exactly as in Haskell.
+ There must be no value declarations, but there can be type signatures for
+values. For example:
+
+ double :: Int -> Int
+
+
+ Fixity declarations are exactly as in Haskell.
+ Type synonym declarations are exactly as in Haskell.
+ A data type declaration can either be given in full, exactly as in Haskell, or it
+can be given abstractly, by omitting the '=' sign and everything that follows. For example:
+
+ data T a b
+
+ In a source program
+ this would declare TA to have no constructors (a GHC extension: see ),
+ but in an hi-boot file it means "I don't know or care what the constructors are".
+ This is the most common form of data type declaration, because it's easy to get right.
+ You can also write out the constructors but, if you do so, you must write
+ it out precisely as in its real definition.
+
+ If you do not write out the constructors, you may need to give a kind
+ annotation (), to tell
+ GHC the kind of the type variable, if it is not "*". (In source files, this is worked out
+ from the way the type variable is used in the constructors.) For example:
+
+ data R (x :: * -> *) y
+
+
+ Class declarations is exactly as in Haskell, except that you may not put
+default method declarations. You can also omit all the class methods entirely.
+
+ Do not include instance declarations. There is a complication to do with
+how the dictionary functions are named. It may well work, but it's not a well-tested feature.
+
+
+
+
+
+
hunk ./ghc/docs/users_guide/separate_compilation.xml 792
+.o-boot.hi-boot:
+ @:
+
+.lhs-boot.o-boot:
+ $(HC) -c $< $(HC_OPTS)
+
+.hs-boot.o-boot:
+ $(HC) -c $< $(HC_OPTS)
+
hunk ./ghc/docs/users_guide/separate_compilation.xml 824
+ Note that the suffix rules are all repeated twice, once
+ for normal Haskell source files, and once for hs-boot
+ files (see ).
hunk ./ghc/docs/users_guide/separate_compilation.xml 841
- preceding suffix rules does the job nicely.
+ preceding suffix rules does the job nicely. These dependencies
+ can be generated automatically by ghc; see
+
hunk ./ghc/docs/users_guide/separate_compilation.xml 845
-
+
+
hunk ./ghc/docs/users_guide/separate_compilation.xml 865
- cool_pgm. ghc -M will
+ cool_pgm. The command ghc -M will
hunk ./ghc/docs/users_guide/separate_compilation.xml 869
- In general, if module A contains the
- line
-
-
-import B ...blah...
-
-
- then ghc -M will generate a dependency line
- of the form:
-
+ In general, ghc -M Foo does the following.
+ For each module M in the set
+ Foo plus all its imports (transitively),
+ it adds to the Makefile:
+
+ A line recording the dependence of the object file on the source file.
hunk ./ghc/docs/users_guide/separate_compilation.xml 876
-A.o : B.hi
+M.o : M.hs
hunk ./ghc/docs/users_guide/separate_compilation.xml 878
-
- If module A contains the line
-
+(or M.lhs if that is the filename you used).
+
+ For each import declaration import X in M,
+ a line recording the dependence of M on X:
hunk ./ghc/docs/users_guide/separate_compilation.xml 883
-import {-# SOURCE #-} B ...blah...
-
-
- then ghc -M will generate a dependency
- line of the form:
-
+M.o : X.hi
+
+ For each import declaration import {-# SOURCE #-} X in M,
+ a line recording the dependence of M on X:
hunk ./ghc/docs/users_guide/separate_compilation.xml 888
-A.o : B.hi-boot
+M.o : X.hi-boot
hunk ./ghc/docs/users_guide/separate_compilation.xml 890
-
hunk ./ghc/docs/users_guide/separate_compilation.xml 891
- hi-boot style interface files.) If
- A imports multiple modules, then there will
- be multiple lines with A.o as the
+ hi-boot style interface files.)
+
+
+ If M imports multiple modules, then there will
+ be multiple lines with M.o as the
hunk ./ghc/docs/users_guide/separate_compilation.xml 897
+ There is no need to list all of the source files as arguments to the ghc -M command;
+ ghc traces the dependencies, just like ghc --make
+ (a new feature in GHC 6.4).
hunk ./ghc/docs/users_guide/separate_compilation.xml 1040
-
-
-
-
- How to compile mutually recursive modules
-
- module system, recursion
- recursion, between modules
-
- Currently, the compiler does not have proper support for
- dealing with mutually recursive modules:
-
-
-module A where
-
-import B
-
-newtype TA = MkTA Int
-
-f :: TB -> TA
-f (MkTB x) = MkTA x
---------
-module B where
-
-import A
-
-data TB = MkTB !Int
-
-g :: TA -> TB
-g (MkTA x) = MkTB x
-
-
- When compiling either module A and B, the compiler will
- try (in vain) to look for the interface file of the other. So,
- to get mutually recursive modules off the ground, you need to
- hand write an interface file for A or B, so as to break the
- loop. These hand-written interface files are called
- hi-boot files, and are placed in a file
- called <module>.hi-boot. To import
- from an hi-boot file instead of the standard
- .hi file, use the following syntax in the
- importing module: hi-boot
- filesimporting,
- hi-boot files
-
-
-import {-# SOURCE #-} A
-
-
- The hand-written interface need only contain the bare
- minimum of information needed to get the bootstrapping process
- started. For example, it doesn't need to contain declarations
- for everything that module
- A exports, only the things required by the
- module that imports A recursively.
-
- For the example at hand, the boot interface file for A
- would look like the following:
-
-
-module A where
-newtype TA = MkTA GHC.Base.Int
-
-
- Notice that we only put the declaration for the newtype
- TA in the hi-boot file,
- not the signature for f, since
- f isn't used by B.
-
- The syntax is similar to a normal Haskell source file, but
- with some important differences:
-
-
-
- Local entities (ones defined in the same hi-boot file may
- be mentioned unqualified, but non-local entities (ones defined in other modules)
- must be qualified with their
- original defining module. Qualifying
- by a module which just re-exports the entity won't do. In
- particular, most Prelude entities aren't
- actually defined in the Prelude (see for
- example GHC.Base.Int in the above
- example). HINT: to find out the fully-qualified name for
- entities in the Prelude (or anywhere for
- that matter), try using GHCi's
- :info command, eg.
-Prelude> :m -Prelude
-> :i IO.IO
--- GHC.IOBase.IO is a type constructor
-newtype GHC.IOBase.IO a
-...
-
-
- Only data, type,
- newtype, class, and
- type signature declarations may be included. You cannot declare
- instances or derive them automatically with
- a deriving clause.
-
-
-For data or newtype declaration, you may omit all
-the constructors, by omitting the '=' and everything that follows it:
-
-module A where
- data TA
-
- In a source program
- this would declare TA to have no constructors (a GHC extension: see ),
- but in an hi-boot file it means "I don't know or care what the constructors are".
- This is the most common form of data type declaration, because it's easy to get right.
-
- You can also write out the constructors but, if you do so, you must write
- it out precisely as in its real definition.
- It is especially delicate if you use a strictness annotation "!",
- with or without an {-# UNPACK #-} pragma. In a source file
- GHC may or may not choose to unbox the argument, but in an hi-boot file it's
- assumed that you express the outcome of this decision.
- (So in the cases where GHC decided not to unpack, you must not use the pragma.)
- Tread with care.
-
- Regardless of whether you write the constructors, you must write all the type parameters,
- including their kinds
- if they are not '*'. (You can give explicit kinds in source files too (),
- but you must do so in hi-boot files.)
-
-
-
- In a class declararation, you may not specify any class operations; that is,
- there can be no where part. If you want to use the class operations in a recursive
- way, declare them in the hi-boot file with separate, overloaded type signatures, thus:
-
- class Num a
- (+) :: Num a => a -> a -> a
-
-
-
-
-
-If M.hi-boot mentions an entity N.f, defined in some other
-module N, then GHC will by default go hunting for N.hi. If module
-N is not yet compiled either, GHC won't look for N.hi-boot; it'll just
-complain. To fix this, in the source file that uses
-import {-# SOURCE #-} M, add
-import {-# SOURCE #-} N(). (The "()" says that you don't want to import anything into
-your current scope, and will prevent unused-import warnings.) You only need this if no other imported module
-depends on N.hi-boot.
-
hunk ./ghc/docs/users_guide/separate_compilation.xml 1042
-
}