[project @ 2005-02-01 17:27:34 by simonpj]
authorsimonpj <unknown>
Tue, 1 Feb 2005 17:27:34 +0000 (17:27 +0000)
committersimonpj <unknown>
Tue, 1 Feb 2005 17:27:34 +0000 (17:27 +0000)
First cut at hs-boot documentation

ghc/docs/users_guide/separate_compilation.xml

index 9a6b7e3..cb80aad 100644 (file)
@@ -612,6 +612,151 @@ $ ghc -c parse/Foo.hs parse/Bar.hs gurgle/Bumble.hs -odir `arch`
 
     </sect2>
 
+    <sect2 id="mutual-recursion">
+      <title>How to compile mutually recursive modules</title>
+
+      <indexterm><primary>module system, recursion</primary></indexterm>
+      <indexterm><primary>recursion, between modules</primary></indexterm>
+
+      <para>GHC supports the compilation of mutually recursive modules.
+      This section explains how.</para>
+
+      <para>Every cycle in the module import graph must be broken by a <filename>hs-boot</filename> file.
+      Suppose that modules <filename>A.hs</filename> and <filename>B.hs</filename> are Haskell source files, 
+      thus:
+<programlisting>
+module A where
+    import B( TB(..) )
+    
+    newtype TA = MkTA Int
+    
+    f :: TB -&#62; TA
+    f (MkTB x) = MkTA x
+
+module B where
+    import {-# SOURCE #-} A( TA(..) )
+    
+    data TB = MkTB !Int
+    
+    g :: TA -&#62; TB
+    g (MkTA x) = MkTB x
+</programlisting>
+<indexterm><primary><literal>hs-boot</literal>
+      files</primary></indexterm> <indexterm><primary>importing,
+      <literal>hi-boot</literal> files</primary></indexterm>
+Here <filename>A</filename> imports <filename>B</filename>, but <filename>B</filename> imports
+<filename>A</filename> with a <literal>{-# SOURCE #-}</literal> pragma, which breaks the
+circular dependency.  For every module <filename>A.hs</filename> that is <literal>{-# SOURCE #-}</literal>-imported
+in this way there must exist a souce file <literal>A.hs-boot</literal>.  This file contains an abbreviated
+version of <filename>A.hs</filename>, thus:
+<programlisting>
+module A where
+    newtype TA = MkTA Int
+</programlisting>
+A <filename>hs-boot</filename> file is compiled by GHC, just like a <filename>hs</filename> file:
+<programlisting>
+  ghc -c A.hs-boot
+</programlisting>
+Just as compiling <filename>A.hs</filename> produces an
+interface file <filename>A.hi</filename>, and an object file
+<filename>A.o</filename>, so compiling <filename>A.hs-boot</filename>
+produces an interface file
+<filename>A.hi-boot</filename>, and an pseudo-object file
+<filename>A.o-boot</filename>.  The interface file
+<filename>A.hi-boot</filename> 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 <filename>A.hi-boot</filename> was
+last brought up to date.
+</para>
+<para>To compile these three files, issue the following commands:
+<programlisting>
+  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
+</programlisting>
+</para>
+<para>There are several points to note here:
+<itemizedlist>
+<listitem>
+  <para>The file <filename>A.hs-boot</filename> is a programmer-written source file.
+  It must live in the same directory as its parent source file <filename>A.hs</filename>.
+  (Currently, if you use a literate source file <filename>A.lhs</filename> you must
+  also use a literate boot file, <filename>A.lhs-boot</filename>.)
+  </para></listitem>
+
+  <listitem><para> The <filename>hi-boot</filename> generated by compiling a <filename>hs-boot</filename>
+  file is in machine-generated binary format.
+  You can display its contents with <command>ghc --show-iface</commaond>. If you 
+  specify a directory for interface files, the <option>-ohidir</option> flag, then that affects
+  <filename>hi-boot</filename> files too.</para></listitem>b
+
+   <listitem><para> 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.</para></listitem>
+   
+   <listitem><para> When a hs-boot file <filename>A.hs-boot</filename> 
+   is compiled, it is checked for scope and type errors.
+   When its parent module <filename>A.hs</filename> is compiled, the two are compared, and
+   an error is reported if the two are inconsistent.
+   </para></listitem>
+   
+   <listitem><para> If hs-boot files are considered distinct from their parent source
+   files, and if a <literal>{-# SOURCE #-}</literal> import is considered to refer to the
+   hs-boot file, then the module import graph must have no cycles.  The <command>ghc -M</command>
+   will report an error if a cycle is found.
+   </para></listitem>
+</itemizedlist>
+</para>
+<para>
+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 <emphasis>everything</emphasis> that module
+      <literal>A</literal> exports, only the things required by the
+      module that imports <literal>A</literal> recursively.</para>
+<para>A hs-boot file is written in a subset of Haskell:
+<itemizedlist>
+<listitem><para> The module header, and import statements, are exactly as in Haskell.</para></listitem>
+<listitem><para> There must be no value declarations, but there can be type signatures for
+values.  For example:
+<programlisting>
+  double :: Int -&#62; Int
+</programlisting>
+</para></listitem>
+<listitem><para> Fixity declarations are exactly as in Haskell.</para></listitem>
+<listitem><para> Type synonym declarations are exactly as in Haskell.</para></listitem>
+<listitem><para> 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:
+<programlisting>
+  data T a b
+</programlisting>
+           In a <emphasis>source</emphasis> program
+         this would declare TA to have no constructors (a GHC extension: see <xref linkend="nullary-types"/>),
+         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 <emphasis>can</emphasis> also write out the constructors but, if you do so, you must write
+         it out precisely as in its real definition.</para>
+         <para>
+           If you do not write out the constructors, you may need to give a kind 
+           annotation (<xref linkend="sec-kinding"/>), 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:
+<programlisting>
+  data R (x :: * -&#62; *) y
+</programlisting>
+</para></listitem>
+<listitem><para> 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.
+</para></listitem>
+<listitem><para> 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.
+ </para></listitem>
+</itemizedlist>
+</para>
+    </sect2>
+
+
     <sect2 id="using-make">
       <title>Using <command>make</command></title>
 
@@ -644,6 +789,15 @@ cool_pgm : $(OBJS)
 .hs.o:
         $(HC) -c $&#60; $(HC_OPTS)
 
+.o-boot.hi-boot:
+        @:
+
+.lhs-boot.o-boot:
+        $(HC) -c $&#60; $(HC_OPTS)
+
+.hs-boot.o-boot:
+        $(HC) -c $&#60; $(HC_OPTS)
+
 # Inter-module dependencies
 Foo.o Foo.hc Foo.s    : Baz.hi          # Foo imports Baz
 Main.o Main.hc Main.s : Foo.hi Baz.hi   # Main imports Foo and Baz
@@ -667,6 +821,9 @@ Main.o Main.hc Main.s : Foo.hi Baz.hi   # Main imports Foo and Baz
       on the source.  The rule says a <filename>.hi</filename> file
       can be made from a <filename>.o</filename> file by
       doing&hellip;nothing.  Which is true.</para>
+      <para> Note that the suffix rules are all repeated twice, once
+      for normal Haskell source files, and once for <filename>hs-boot</filename>
+      files (see <xref linkend="mutual-recursion"/>).
 
       <para>Note the inter-module dependencies at the end of the
       Makefile, which take the form</para>
@@ -681,9 +838,12 @@ Foo.o Foo.hc Foo.s    : Baz.hi          # Foo imports Baz
       <literal>Baz.hi</literal>, then the out-of-date file must be
       brought up to date.  To bring it up to date,
       <literal>make</literal> looks for a rule to do so; one of the
-      preceding suffix rules does the job nicely.</para>
+      preceding suffix rules does the job nicely.  These dependencies
+      can be generated automatically by <command>ghc</command>; see 
+      <xref linkend="sec-makefile-dependencies"/></para>
 
-      <sect3 id="sec-makefile-dependencies">
+ </sect2>
+      <sect2 id="sec-makefile-dependencies">
        <title>Dependency generation</title>
        <indexterm><primary>dependencies in Makefiles</primary></indexterm>
        <indexterm><primary>Makefile dependencies</primary></indexterm>
@@ -702,42 +862,41 @@ depend :
        <para>Now, before you start compiling, and any time you change
         the <literal>imports</literal> in your program, do
         <command>make depend</command> before you do <command>make
-        cool&lowbar;pgm</command>.  <command>ghc -M</command> will
+        cool&lowbar;pgm</command>.  The command <command>ghc -M</command> will
         append the needed dependencies to your
         <filename>Makefile</filename>.</para>
 
-       <para>In general, if module <literal>A</literal> contains the
-        line
-
+       <para>In general, <command>ghc -M Foo</command> does the following.
+       For each module <literal>M</literal> in the set 
+       <literal>Foo</literal> plus all its imports (transitively),
+       it adds to the Makefile:
+       <itemizedlist>
+       <listitem><para>A line recording the dependence of the object file on the source file.
 <programlisting>
-import B ...blah...
+M.o : M.hs
 </programlisting>
-
-       then <command>ghc -M</command> will generate a dependency line
-        of the form:
-
+(or <literal>M.lhs</literal> if that is the filename you used).
+       </para></listitem>
+       <listitem><para> For each import declaration <literal>import X</literal> in <literal>M</literal>,
+       a line recording the dependence of <literal>M</literal> on <literal>X</literal>:
 <programlisting>
-A.o : B.hi
-</programlisting>
-
-       If module <literal>A</literal> contains the line
-
-<programlisting>
-import {-# SOURCE #-} B ...blah...
-</programlisting>
-
-       then <command>ghc -M</command> will generate a dependency
-       line of the form:
-
+M.o : X.hi
+</programlisting></para></listitem>
+       <listitem><para> For each import declaration <literal>import {-# SOURCE #-} X</literal> in <literal>M</literal>,
+       a line recording the dependence of <literal>M</literal> on <literal>X</literal>:
 <programlisting>
-A.o : B.hi-boot
+M.o : X.hi-boot
 </programlisting>
-
        (See <xref linkend="mutual-recursion"/> for details of
-       <literal>hi-boot</literal> style interface files.)  If
-       <literal>A</literal> imports multiple modules, then there will
-       be multiple lines with <filename>A.o</filename> as the
+       <literal>hi-boot</literal> style interface files.)
+      </para></listitem>
+        </itemizedlist> 
+       If <literal>M</literal> imports multiple modules, then there will
+       be multiple lines with <filename>M.o</filename> as the
        target.</para>
+       <para>There is no need to list all of the source files as arguments to the <command>ghc -M</command> command;
+       <command>ghc</command> traces the dependencies, just like <command>ghc --make</command>
+       (a new feature in GHC 6.4).</para>
 
         <para>By default, <command>ghc -M</command> generates all the
         dependencies, and then concatenates them onto the end of
@@ -878,156 +1037,8 @@ ghc -M -optdep-f -optdep.depend ...
          </varlistentry>
        </variablelist>
 
-      </sect3>
     </sect2>
 
-    <sect2 id="mutual-recursion">
-      <title>How to compile mutually recursive modules</title>
-
-      <indexterm><primary>module system, recursion</primary></indexterm>
-      <indexterm><primary>recursion, between modules</primary></indexterm>
-
-      <para>Currently, the compiler does not have proper support for
-      dealing with mutually recursive modules:</para>
-
-<programlisting>
-module A where
-
-import B
-
-newtype TA = MkTA Int
-
-f :: TB -&#62; TA
-f (MkTB x) = MkTA x
---------
-module B where
-
-import A
-
-data TB = MkTB !Int
-
-g :: TA -&#62; TB
-g (MkTA x) = MkTB x
-</programlisting>
-
-      <para>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
-      <literal>hi-boot</literal> files, and are placed in a file
-      called <filename>&lt;module&gt;.hi-boot</filename>.  To import
-      from an <literal>hi-boot</literal> file instead of the standard
-      <filename>.hi</filename> file, use the following syntax in the
-      importing module: <indexterm><primary><literal>hi-boot</literal>
-      files</primary></indexterm> <indexterm><primary>importing,
-      <literal>hi-boot</literal> files</primary></indexterm></para>
-
-<programlisting>
-import {-# SOURCE #-} A
-</programlisting>
-
-      <para>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 <emphasis>everything</emphasis> that module
-      <literal>A</literal> exports, only the things required by the
-      module that imports <literal>A</literal> recursively.</para>
-
-      <para>For the example at hand, the boot interface file for A
-      would look like the following:</para>
-
-<programlisting>
-module A where
-newtype TA = MkTA GHC.Base.Int
-</programlisting>
-
-      <para>Notice that we only put the declaration for the newtype
-      <literal>TA</literal> in the <literal>hi-boot</literal> file,
-      not the signature for <function>f</function>, since
-      <function>f</function> isn't used by <literal>B</literal>.</para>
-
-      <para>The syntax is similar to a normal Haskell source file, but
-      with some important differences:</para>
-
-      <itemizedlist>
-       <listitem>
-         <para>Local entities (ones defined in the same <literal>hi-boot</literal> file may
-          be mentioned unqualified, but non-local entities (ones defined in other modules)
-          must be qualified with their
-         <emphasis>original</emphasis> defining module.  Qualifying
-         by a module which just re-exports the entity won't do.  In
-         particular, most <literal>Prelude</literal> entities aren't
-         actually defined in the <literal>Prelude</literal> (see for
-         example <literal>GHC.Base.Int</literal> in the above
-         example).  HINT: to find out the fully-qualified name for
-         entities in the <literal>Prelude</literal> (or anywhere for
-         that matter), try using GHCi's
-         <literal>:info</literal> command, eg.</para>
-<programlisting>Prelude> :m -Prelude
-> :i IO.IO
--- GHC.IOBase.IO is a type constructor
-newtype GHC.IOBase.IO a
-...</programlisting>
-       </listitem>
-       <listitem>
-         <para>Only <literal>data</literal>, <literal>type</literal>,
-         <literal>newtype</literal>, <literal>class</literal>, and
-         type signature declarations may be included. You cannot declare
-         <literal>instances</literal> or derive them automatically with 
-          a <literal>deriving</literal> clause.</para>
-</listitem>
-
-<listitem> <para>For <literal>data</literal> or <literal>newtype</literal> declaration, you may omit all
-the constructors, by omitting the '=' and everything that follows it:
-<programlisting>
-module A where
-  data TA
-</programlisting>
-           In a <emphasis>source</emphasis> program
-         this would declare TA to have no constructors (a GHC extension: see <xref linkend="nullary-types"/>),
-         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.</para>
-         <para>
-         You <emphasis>can</emphasis> 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 <literal>{-# UNPACK #-}</literal> 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 <emphasis>outcome</emphasis> of this decision.
-           (So in the cases where GHC decided not to unpack, you must not use the pragma.)
-           Tread with care.</para>
-         <para>
-           Regardless of whether you write the constructors, you must write all the type parameters,
-           <emphasis>including their kinds</emphasis>
-           if they are not '*'.  (You can give explicit kinds in source files too (<xref linkend="sec-kinding"/>),
-           but you <emphasis>must</emphasis> do so in hi-boot files.)</para>
-       </listitem>
-
-<listitem><para>
-       In a <literal>class</literal> declararation, you may not specify any class operations; that is, 
-         there can be no <literal>where</literal> part.  If you want to use the class operations in a recursive
-         way, declare them in the <literal>hi-boot</literal> file with separate, overloaded type signatures, thus:
-<programlisting>
-   class Num a
-   (+) :: Num a => a -> a -> a
-</programlisting>
-         </para>
-       </listitem>
-      </itemizedlist>
-
-<para>If <literal>M.hi-boot</literal> mentions an entity <literal>N.f</literal>, defined in some other
-module <literal>N</literal>, then GHC will by default go hunting for <literal>N.hi</literal>. If module
-<literal>N</literal> is not yet compiled either, GHC won't look for <literal>N.hi-boot</literal>; it'll just
-complain.  To fix this, in the source file that uses 
-<literal>import {-# SOURCE #-} M</literal>, add 
-<literal>import {-# SOURCE #-} N()</literal>.  (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 <literal>N.hi-boot</literal>.</para>
-
-    </sect2>
-
-
     <sect2 id="orphan-modules">
       <title>Orphan modules and instance declarations</title>