Skip to content

Commit

Permalink
Merge pull request #9400 from BinderDavid/howto-use-backpack
Browse files Browse the repository at this point in the history
Move documentation about how to use backpack
  • Loading branch information
mergify[bot] authored Nov 8, 2023
2 parents 156d8b2 + e46bf27 commit 813fd5f
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 131 deletions.
2 changes: 1 addition & 1 deletion doc/buildinfo-fields-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ pkgconfig-depends
virtual-modules
* Monoidal field
* Available since ``cabal-version: 2.2``.
* Documentation of :pkg-field:`virtual-modules`
* Documentation of :pkg-field:`library:virtual-modules`

.. math::
\mathrm{commalist}\left({\left(\mathop{\mathit{upper}}{\left\{ \mathop{\mathit{alpha\text{-}num}}\mid[\mathop{\mathord{``}\mathtt{\text{'}}\mathord{"}}\mathop{\mathord{``}\mathtt{\text{_}}\mathord{"}}] \right\}}^\ast_{}\right)}^+_{\mathop{\mathord{``}\mathtt{\text{.}}\mathord{"}}}\right)
Expand Down
133 changes: 3 additions & 130 deletions doc/cabal-package-description-file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ The library section should contain the following fields:

Supported only in GHC 8.2 and later. A list of `module signatures <https://downloads.haskell.org/~ghc/master/users-guide/separate_compilation.html#module-signatures>`__ required by this package.

Module signatures are part of the Backpack_ extension to
Module signatures are part of the :ref:`Backpack` extension to
the Haskell module system.

Packages that do not export any modules and only export required signatures
Expand Down Expand Up @@ -2211,7 +2211,7 @@ system-dependent values for these fields.

See the :pkg-field:`library:signatures` field for more details.

Mixin packages are part of the Backpack_ extension to the
Mixin packages are part of the :ref:`Backpack` extension to the
Haskell module system.

The matching of the module signatures required by a
Expand All @@ -2224,7 +2224,7 @@ system-dependent values for these fields.

.. Warning::

Backpack_ has the limitation that implementation modules that instantiate
:ref:`Backpack` has the limitation that implementation modules that instantiate
signatures required by a :pkg-field:`build-depends` dependency can't
reside in the same component that has the dependency. They must reside
in a different package dependency, or at least in a separate internal
Expand Down Expand Up @@ -2923,16 +2923,6 @@ Right now :pkg-field:`executable:main-is` modules are not supported on
(e.g. by a ``configure`` script). Autogenerated header files are not
packaged by ``sdist`` command.

Virtual modules
---------------

TBW

.. pkg-field:: virtual-modules: module list
:since: 2.2

TBW


.. _accessing-data-files:

Expand Down Expand Up @@ -3305,123 +3295,6 @@ a few options:
library for all or part of the work. One option is to copy the source
of ``Distribution.Simple``, and alter it for your needs. Good luck.
.. _Backpack:
Backpack
--------
Cabal and GHC jointly support Backpack, an extension to Haskell's module
system which makes it possible to parametrize a package over some
modules, which can be instantiated later arbitrarily by a user. This
means you can write a library to be agnostic over some data
representation, and then instantiate it several times with different
data representations. Like C++ templates, instantiated packages are
recompiled for each instantiation, which means you do not pay any
runtime cost for parametrizing packages in this way. Backpack modules
are somewhat experimental; while fully supported by cabal-install, they are currently
`not supported by Stack <https://github.com/commercialhaskell/stack/issues/2540>`__.
A Backpack package is defined by use of the
:pkg-field:`library:signatures` field, or by (transitive) dependency on
a package that defines some requirements. To define a parametrized
package, define a signature file (file extension ``hsig``) that
specifies the signature of the module you want to parametrize over, and
add it to your Cabal file in the :pkg-field:`library:signatures` field.
.. code-block:: haskell
:caption: .hsig
signature Str where
data Str
concat :: [Str] -> Str
.. code-block:: cabal
:caption: parametrized.cabal
cabal-version: 2.2
name: parametrized
library
build-depends: base
signatures: Str
exposed-modules: MyModule
You can define any number of regular modules (e.g., ``MyModule``) that
import signatures and use them as regular modules.
If you are familiar with ML modules, you might now expect there to be
some way to apply the parametrized package with an implementation of
the ``Str`` module to get a concrete instantiation of the package.
Backpack operates slightly differently with a concept of *mix-in
linking*, where you provide an implementation of ``Str`` simply by
bringing another module into scope with the same name as the
requirement. For example, if you had a package ``str-impl`` that provided a
module named ``Str``, instantiating ``parametrized`` is as simple as
just depending on both ``str-impl`` and ``parametrized``:
.. code-block:: cabal
:caption: combined.cabal
cabal-version: 2.2
name: combined
library
build-depends: base, str-impl, parametrized
Note that due to technical limitations, you cannot directly define
``Str`` in the ``combined`` library; it must be placed in its own
library (you can use :ref:`Sublibraries <sublibs>` to conveniently
define a sub-library).
However, a more common situation is that your names don't match up
exactly. The :pkg-field:`library:mixins` field can be used to rename
signatures and modules to line up names as necessary. If you have
a requirement ``Str`` and an implementation ``Data.Text``, you can
line up the names in one of two ways:
* Rename the requirement to match the implementation:
``mixins: parametrized requires (Str as Data.Text)``
* Rename the implementation to match the requirement:
``mixins: text (Data.Text as Str)``
The :pkg-field:`library:mixins` field can also be used to disambiguate
between multiple instantiations of the same package; for each
instantiation of the package, give it a separate entry in mixins with
the requirements and provided modules renamed to be distinct.
.. code-block:: cabal
:caption: .cabal
cabal-version: 2.2
name: double-combined
library
build-depends: base, text, bytestring, parametrized
mixins:
parametrized (MyModule as MyModule.Text) requires (Str as Data.Text),
parametrized (MyModule as MyModule.BS) requires (Str as Data.ByteString)
Intensive use of Backpack sometimes involves creating lots of small
parametrized libraries; :ref:`Sublibraries <sublibs>` can be used
to define all of these libraries in a single package without having to
create many separate Cabal packages. You may also find it useful to use
:pkg-field:`library:reexported-modules` to reexport instantiated
libraries to Backpack-unware users (e.g., Backpack can be used entirely
as an implementation detail.)
Backpack imposes a limitation on Template Haskell that goes beyond the usual TH
stage restriction: it's not possible to splice TH code imported from a
compilation unit that is still "indefinite", that is, a unit for which some
module signatures still haven't been matched with implementations. The reason
is that indefinite units are typechecked, but not compiled, so there's no
actual TH code to run while splicing. Splicing TH code from a definite
compilation unit into an indefinite one works normally.
For more information about Backpack, check out the
`GHC wiki page <https://gitlab.haskell.org/ghc/ghc/-/wikis/backpack>`__.
.. include:: references.inc
.. rubric:: Footnotes
Expand Down
117 changes: 117 additions & 0 deletions doc/how-to-use-backpack.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
.. _Backpack:

How to use Backpack modules
===========================

Cabal and GHC jointly support Backpack, an extension to Haskell's module
system which makes it possible to parametrize a package over some
modules, which can be instantiated later arbitrarily by a user. This
means you can write a library to be agnostic over some data
representation, and then instantiate it several times with different
data representations. Like C++ templates, instantiated packages are
recompiled for each instantiation, which means you do not pay any
runtime cost for parametrizing packages in this way. Backpack modules
are somewhat experimental; while fully supported by cabal-install, they are currently
`not supported by Stack <https://github.com/commercialhaskell/stack/issues/2540>`__.

A Backpack package is defined by use of the
:pkg-field:`library:signatures` field, or by (transitive) dependency on
a package that defines some requirements. To define a parametrized
package, define a signature file (file extension ``hsig``) that
specifies the signature of the module you want to parametrize over, and
add it to your Cabal file in the :pkg-field:`library:signatures` field.

.. code-block:: haskell
:caption: .hsig
signature Str where
data Str
concat :: [Str] -> Str
.. code-block:: cabal
:caption: parametrized.cabal
cabal-version: 2.2
name: parametrized
library
build-depends: base
signatures: Str
exposed-modules: MyModule
You can define any number of regular modules (e.g., ``MyModule``) that
import signatures and use them as regular modules.

If you are familiar with ML modules, you might now expect there to be
some way to apply the parametrized package with an implementation of
the ``Str`` module to get a concrete instantiation of the package.
Backpack operates slightly differently with a concept of *mix-in
linking*, where you provide an implementation of ``Str`` simply by
bringing another module into scope with the same name as the
requirement. For example, if you had a package ``str-impl`` that provided a
module named ``Str``, instantiating ``parametrized`` is as simple as
just depending on both ``str-impl`` and ``parametrized``:

.. code-block:: cabal
:caption: combined.cabal
cabal-version: 2.2
name: combined
library
build-depends: base, str-impl, parametrized
Note that due to technical limitations, you cannot directly define
``Str`` in the ``combined`` library; it must be placed in its own
library (you can use :ref:`Sublibraries <sublibs>` to conveniently
define a sub-library).

However, a more common situation is that your names don't match up
exactly. The :pkg-field:`library:mixins` field can be used to rename
signatures and modules to line up names as necessary. If you have
a requirement ``Str`` and an implementation ``Data.Text``, you can
line up the names in one of two ways:

* Rename the requirement to match the implementation:
``mixins: parametrized requires (Str as Data.Text)``
* Rename the implementation to match the requirement:
``mixins: text (Data.Text as Str)``

The :pkg-field:`library:mixins` field can also be used to disambiguate
between multiple instantiations of the same package; for each
instantiation of the package, give it a separate entry in mixins with
the requirements and provided modules renamed to be distinct.

.. code-block:: cabal
:caption: .cabal
cabal-version: 2.2
name: double-combined
library
build-depends: base, text, bytestring, parametrized
mixins:
parametrized (MyModule as MyModule.Text) requires (Str as Data.Text),
parametrized (MyModule as MyModule.BS) requires (Str as Data.ByteString)
Intensive use of Backpack sometimes involves creating lots of small
parametrized libraries; :ref:`Sublibraries <sublibs>` can be used
to define all of these libraries in a single package without having to
create many separate Cabal packages. You may also find it useful to use
:pkg-field:`library:reexported-modules` to reexport instantiated
libraries to Backpack-unware users (e.g., Backpack can be used entirely
as an implementation detail.)

Backpack imposes a limitation on Template Haskell that goes beyond the usual TH
stage restriction: it's not possible to splice TH code imported from a
compilation unit that is still "indefinite", that is, a unit for which some
module signatures still haven't been matched with implementations. The reason
is that indefinite units are typechecked, but not compiled, so there's no
actual TH code to run while splicing. Splicing TH code from a definite
compilation unit into an indefinite one works normally.

For more information about Backpack, check out the
`GHC wiki page <https://gitlab.haskell.org/ghc/ghc/-/wikis/backpack>`__.

1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Welcome to the Cabal User Guide

how-to-package-haskell-code
how-to-build-like-nix
how-to-use-backpack
how-to-report-bugs

.. toctree::
Expand Down

0 comments on commit 813fd5f

Please sign in to comment.